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,680 @@
|
|
|
1
|
+
"""Tools for maintaining the archive of opsim output and metadata."""
|
|
2
|
+
|
|
3
|
+
__all__ = [
|
|
4
|
+
"make_sim_data_dir",
|
|
5
|
+
"drive_sim",
|
|
6
|
+
"find_latest_prenight_sim_for_nights",
|
|
7
|
+
"fetch_sim_for_nights",
|
|
8
|
+
"fetch_obsloctap_visits",
|
|
9
|
+
"fetch_sim_stats_for_night",
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
import hashlib
|
|
13
|
+
import logging
|
|
14
|
+
import lzma
|
|
15
|
+
import os
|
|
16
|
+
import pickle
|
|
17
|
+
import shutil
|
|
18
|
+
import socket
|
|
19
|
+
from datetime import date, datetime, timedelta
|
|
20
|
+
from numbers import Integral, Number
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
from tempfile import TemporaryDirectory
|
|
23
|
+
from typing import Any, Optional, Sequence, cast
|
|
24
|
+
from zoneinfo import ZoneInfo
|
|
25
|
+
|
|
26
|
+
import numpy as np
|
|
27
|
+
import pandas as pd
|
|
28
|
+
import rubin_scheduler
|
|
29
|
+
import yaml
|
|
30
|
+
from astropy.time import Time
|
|
31
|
+
from lsst.resources import ResourcePath
|
|
32
|
+
from pandas.api.types import is_numeric_dtype
|
|
33
|
+
from rubin_scheduler.scheduler import sim_runner
|
|
34
|
+
from rubin_scheduler.scheduler.model_observatory import ModelObservatory
|
|
35
|
+
from rubin_scheduler.scheduler.schedulers import CoreScheduler
|
|
36
|
+
from rubin_scheduler.scheduler.utils import SchemaConverter
|
|
37
|
+
from rubin_scheduler.site_models.almanac import Almanac
|
|
38
|
+
|
|
39
|
+
from rubin_sim import maf
|
|
40
|
+
from rubin_sim.maf.stackers import BaseStacker
|
|
41
|
+
from rubin_sim.maf.utils.opsim_utils import get_sim_data
|
|
42
|
+
from rubin_sim.sim_archive.prenightindex import get_prenight_index, select_latest_prenight_sim
|
|
43
|
+
from rubin_sim.sim_archive.util import dayobs_to_date
|
|
44
|
+
from rubin_sim.sim_archive.vseqarchive import compute_nightly_stats, get_visits
|
|
45
|
+
from rubin_sim.sim_archive.vseqmetadata import VisitSequenceArchiveMetadata
|
|
46
|
+
|
|
47
|
+
LOGGER = logging.getLogger(__name__)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def make_sim_data_dir(
|
|
51
|
+
observations: np.recarray,
|
|
52
|
+
reward_df: pd.DataFrame | None = None,
|
|
53
|
+
obs_rewards: pd.DataFrame | None = None,
|
|
54
|
+
in_files: dict = {},
|
|
55
|
+
sim_runner_kwargs: dict = {},
|
|
56
|
+
tags: list = [],
|
|
57
|
+
label: str | None = None,
|
|
58
|
+
data_path: str | Path | None = None,
|
|
59
|
+
opsim_metadata: dict | None = None,
|
|
60
|
+
) -> Path | str:
|
|
61
|
+
"""Create or fill a local simulation archive directory.
|
|
62
|
+
|
|
63
|
+
Parameters
|
|
64
|
+
----------
|
|
65
|
+
observations : `np.recarray`
|
|
66
|
+
The observations data, in the "obs" format as accepted and
|
|
67
|
+
created by `SchemaConverter`.
|
|
68
|
+
reward_df : `pd.DataFrame`, optional
|
|
69
|
+
The reward data, by default None.
|
|
70
|
+
obs_rewards : `pd.DataFrame`, optional
|
|
71
|
+
The observation rewards data, by default None.
|
|
72
|
+
in_files : `dict`, optional
|
|
73
|
+
Additional input files to be included in the archive,
|
|
74
|
+
by default {}.
|
|
75
|
+
sim_runner_kwargs : `dict`, optional
|
|
76
|
+
Additional simulation runner keyword arguments, by default {}.
|
|
77
|
+
tags : `list` [`str`], optional
|
|
78
|
+
A list of tags/keywords to be included in the metadata, by
|
|
79
|
+
default [].
|
|
80
|
+
label : `str`, optional
|
|
81
|
+
A label to be included in the metadata, by default None.
|
|
82
|
+
data_path : `str` or `Path`, optional
|
|
83
|
+
The path to the simulation archive directory, by default None.
|
|
84
|
+
opsim_metadata : `dict`
|
|
85
|
+
Metadata to be included.
|
|
86
|
+
|
|
87
|
+
Returns
|
|
88
|
+
-------
|
|
89
|
+
data_dir : `Path` or `TemporaryDirectory`
|
|
90
|
+
The temporary directory containing the simulation archive.
|
|
91
|
+
"""
|
|
92
|
+
if data_path is None:
|
|
93
|
+
data_dir = TemporaryDirectory()
|
|
94
|
+
data_path = Path(data_dir.name)
|
|
95
|
+
else:
|
|
96
|
+
data_dir = None
|
|
97
|
+
|
|
98
|
+
if not isinstance(data_path, Path):
|
|
99
|
+
data_path = Path(data_path)
|
|
100
|
+
|
|
101
|
+
files = {}
|
|
102
|
+
|
|
103
|
+
# Save the observations
|
|
104
|
+
files["observations"] = {"name": "opsim.db"}
|
|
105
|
+
opsim_output_fname = data_path.joinpath(files["observations"]["name"])
|
|
106
|
+
SchemaConverter().obs2opsim(observations, filename=opsim_output_fname)
|
|
107
|
+
|
|
108
|
+
# Save the rewards
|
|
109
|
+
if reward_df is not None and obs_rewards is not None:
|
|
110
|
+
files["rewards"] = {"name": "rewards.h5"}
|
|
111
|
+
rewards_fname = data_path.joinpath(files["rewards"]["name"])
|
|
112
|
+
if reward_df is not None:
|
|
113
|
+
reward_df.to_hdf(rewards_fname, key="reward_df")
|
|
114
|
+
if obs_rewards is not None:
|
|
115
|
+
obs_rewards.to_hdf(rewards_fname, key="obs_rewards")
|
|
116
|
+
|
|
117
|
+
# Save basic statistics
|
|
118
|
+
files["statistics"] = {"name": "obs_stats.txt"}
|
|
119
|
+
stats_fname = data_path.joinpath(files["statistics"]["name"])
|
|
120
|
+
with open(stats_fname, "w") as stats_io:
|
|
121
|
+
print(SchemaConverter().obs2opsim(observations).describe().T.to_csv(sep="\t"), file=stats_io)
|
|
122
|
+
|
|
123
|
+
# Add supplied files
|
|
124
|
+
for file_type, fname in in_files.items():
|
|
125
|
+
files[file_type] = {"name": Path(fname).name}
|
|
126
|
+
try:
|
|
127
|
+
shutil.copyfile(fname, data_path.joinpath(files[file_type]["name"]))
|
|
128
|
+
except shutil.SameFileError:
|
|
129
|
+
pass
|
|
130
|
+
|
|
131
|
+
# Add file hashes
|
|
132
|
+
for file_type in files:
|
|
133
|
+
fname = data_path.joinpath(files[file_type]["name"])
|
|
134
|
+
with open(fname, "rb") as file_io:
|
|
135
|
+
content = file_io.read()
|
|
136
|
+
|
|
137
|
+
files[file_type]["md5"] = hashlib.md5(content).hexdigest()
|
|
138
|
+
|
|
139
|
+
def convert_mjd_to_dayobs(mjd: float) -> str:
|
|
140
|
+
# Use dayObs defn. from SITCOMTN-32: https://sitcomtn-032.lsst.io/
|
|
141
|
+
evening_local_mjd = np.floor(mjd - 0.5).astype(int)
|
|
142
|
+
evening_local_iso = Time(evening_local_mjd, format="mjd").iso[:10]
|
|
143
|
+
assert isinstance(evening_local_iso, str)
|
|
144
|
+
return evening_local_iso
|
|
145
|
+
|
|
146
|
+
if opsim_metadata is None:
|
|
147
|
+
opsim_metadata = {}
|
|
148
|
+
|
|
149
|
+
opsim_metadata["scheduler_version"] = rubin_scheduler.__version__
|
|
150
|
+
opsim_metadata["host"] = socket.getfqdn()
|
|
151
|
+
opsim_metadata["username"] = os.environ["USER"]
|
|
152
|
+
|
|
153
|
+
simulation_dates = {}
|
|
154
|
+
if "sim_start_mjd" in sim_runner_kwargs:
|
|
155
|
+
simulation_dates["first"] = convert_mjd_to_dayobs(sim_runner_kwargs["sim_start_mjd"])
|
|
156
|
+
|
|
157
|
+
if "sim_duration" in sim_runner_kwargs:
|
|
158
|
+
simulation_dates["last"] = convert_mjd_to_dayobs(
|
|
159
|
+
sim_runner_kwargs["sim_start_mjd"] + sim_runner_kwargs["sim_duration"] - 1
|
|
160
|
+
)
|
|
161
|
+
else:
|
|
162
|
+
simulation_dates["first"] = convert_mjd_to_dayobs(observations["mjd"].min())
|
|
163
|
+
simulation_dates["last"] = convert_mjd_to_dayobs(observations["mjd"].max())
|
|
164
|
+
|
|
165
|
+
if len(sim_runner_kwargs) > 0:
|
|
166
|
+
opsim_metadata["sim_runner_kwargs"] = {}
|
|
167
|
+
for key, value in sim_runner_kwargs.items():
|
|
168
|
+
# Cast numpy number types to ints, floats, and reals to avoid
|
|
169
|
+
# confusing the yaml module.
|
|
170
|
+
match value:
|
|
171
|
+
case bool():
|
|
172
|
+
opsim_metadata["sim_runner_kwargs"][key] = value
|
|
173
|
+
case Integral():
|
|
174
|
+
opsim_metadata["sim_runner_kwargs"][key] = int(value)
|
|
175
|
+
case Number():
|
|
176
|
+
opsim_metadata["sim_runner_kwargs"][key] = float(value)
|
|
177
|
+
case _:
|
|
178
|
+
opsim_metadata["sim_runner_kwargs"][key] = str(value)
|
|
179
|
+
|
|
180
|
+
opsim_metadata["simulated_dates"] = simulation_dates
|
|
181
|
+
opsim_metadata["files"] = files
|
|
182
|
+
|
|
183
|
+
if len(tags) > 0:
|
|
184
|
+
for tag in tags:
|
|
185
|
+
assert isinstance(tag, str), "Tags must be strings."
|
|
186
|
+
opsim_metadata["tags"] = tags
|
|
187
|
+
|
|
188
|
+
if label is not None:
|
|
189
|
+
assert isinstance(label, str), "The sim label must be a string."
|
|
190
|
+
opsim_metadata["label"] = label
|
|
191
|
+
|
|
192
|
+
sim_metadata_fname = data_path.joinpath("sim_metadata.yaml")
|
|
193
|
+
with open(sim_metadata_fname, "w") as sim_metadata_io:
|
|
194
|
+
print(yaml.dump(opsim_metadata, indent=4), file=sim_metadata_io)
|
|
195
|
+
|
|
196
|
+
files["metadata"] = {"name": sim_metadata_fname}
|
|
197
|
+
|
|
198
|
+
if data_dir is not None:
|
|
199
|
+
# If we created a temporary directory, if we do not return it, it
|
|
200
|
+
# will get automatically cleaned up, losing our work.
|
|
201
|
+
# So, return it.
|
|
202
|
+
return data_dir
|
|
203
|
+
|
|
204
|
+
return data_path
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def drive_sim(
|
|
208
|
+
observatory: ModelObservatory,
|
|
209
|
+
scheduler: CoreScheduler,
|
|
210
|
+
label: str | None = None,
|
|
211
|
+
tags: list = [],
|
|
212
|
+
script: str | None = None,
|
|
213
|
+
notebook: str | None = None,
|
|
214
|
+
opsim_metadata: dict | None = None,
|
|
215
|
+
**kwargs: Any,
|
|
216
|
+
) -> tuple:
|
|
217
|
+
"""Run a simulation and archive the results.
|
|
218
|
+
|
|
219
|
+
Parameters
|
|
220
|
+
----------
|
|
221
|
+
observatory : `ModelObservatory`
|
|
222
|
+
The model for the observatory.
|
|
223
|
+
scheduler : `CoreScheduler`
|
|
224
|
+
The scheduler to use.
|
|
225
|
+
archive_uri : `str`, optional
|
|
226
|
+
The root URI of the archive resource into which the results should
|
|
227
|
+
be stored. Defaults to None.
|
|
228
|
+
label : `str`, optional
|
|
229
|
+
The label for the simulation in the archive. Defaults to None.
|
|
230
|
+
tags : `list` of `str`, optional
|
|
231
|
+
The tags for the simulation in the archive. Defaults to an
|
|
232
|
+
empty list.
|
|
233
|
+
script : `str`
|
|
234
|
+
The filename of the script producing this simulation.
|
|
235
|
+
Defaults to None.
|
|
236
|
+
notebook : `str`, optional
|
|
237
|
+
The filename of the notebook producing the simulation.
|
|
238
|
+
Defaults to None.
|
|
239
|
+
opsim_metadata : `dict`, optional
|
|
240
|
+
Extra metadata to store in the archive.
|
|
241
|
+
|
|
242
|
+
Returns
|
|
243
|
+
-------
|
|
244
|
+
observatory : `ModelObservatory`
|
|
245
|
+
The model for the observatory.
|
|
246
|
+
scheduler : `CoreScheduler`
|
|
247
|
+
The scheduler used.
|
|
248
|
+
observations : `numpy.recarray`
|
|
249
|
+
The observations produced.
|
|
250
|
+
reward_df : `pandas.DataFrame`, optional
|
|
251
|
+
The table of rewards. Present if ``record_rewards``
|
|
252
|
+
or ``scheduler.keep_rewards`` is True.
|
|
253
|
+
obs_rewards : `pandas.Series`, optional
|
|
254
|
+
The mapping of entries in reward_df to observations. Present if
|
|
255
|
+
``record_rewards``` or ``scheduler.keep_rewards`` is True.
|
|
256
|
+
resource_path : `ResourcePath`, optional
|
|
257
|
+
The resource path to the archive of the simulation. Present if
|
|
258
|
+
``archive_uri`` was set.
|
|
259
|
+
|
|
260
|
+
Notes
|
|
261
|
+
-----
|
|
262
|
+
Additional parameters not described above will be passed into
|
|
263
|
+
``sim_runner``.
|
|
264
|
+
|
|
265
|
+
If the ``archive_uri`` parameter is not supplied, ``sim_runner`` is run
|
|
266
|
+
directly, so that ``drive_sim`` can act as a drop-in replacement of
|
|
267
|
+
``sim_runner``.
|
|
268
|
+
|
|
269
|
+
In a jupyter notebook, the notebook can be saved for the notebook
|
|
270
|
+
paramater using ``%notebook $notebook_fname`` (where ``notebook_fname``
|
|
271
|
+
is variable holding the filename for the notebook) in the cell prior
|
|
272
|
+
to calling ``drive_sim``.
|
|
273
|
+
"""
|
|
274
|
+
if "record_rewards" in kwargs:
|
|
275
|
+
if kwargs["record_rewards"] and not scheduler.keep_rewards:
|
|
276
|
+
raise ValueError("To keep rewards, scheduler.keep_rewards must be True")
|
|
277
|
+
else:
|
|
278
|
+
kwargs["record_rewards"] = scheduler.keep_rewards
|
|
279
|
+
|
|
280
|
+
in_files = {}
|
|
281
|
+
if script is not None:
|
|
282
|
+
in_files["script"] = script
|
|
283
|
+
|
|
284
|
+
if notebook is not None:
|
|
285
|
+
in_files["notebook"] = notebook
|
|
286
|
+
|
|
287
|
+
with TemporaryDirectory() as local_data_dir:
|
|
288
|
+
LOGGER.debug(f"Using temporary directory {local_data_dir}.")
|
|
289
|
+
# We want to store the state of the scheduler at the start of
|
|
290
|
+
# the sim, so we need to save it now before we run the simulation.
|
|
291
|
+
scheduler_path = Path(local_data_dir).joinpath("scheduler.pickle.xz")
|
|
292
|
+
with lzma.open(scheduler_path, "wb", format=lzma.FORMAT_XZ) as pio:
|
|
293
|
+
pickle.dump(scheduler, pio)
|
|
294
|
+
in_files["scheduler"] = scheduler_path.as_posix()
|
|
295
|
+
|
|
296
|
+
LOGGER.debug("About to call sim_runner.")
|
|
297
|
+
sim_results = sim_runner(observatory, scheduler, **kwargs)
|
|
298
|
+
LOGGER.debug("sim_runner complete.")
|
|
299
|
+
|
|
300
|
+
observations = sim_results[2]
|
|
301
|
+
reward_df = sim_results[3] if scheduler.keep_rewards else None
|
|
302
|
+
obs_rewards = sim_results[4] if scheduler.keep_rewards else None
|
|
303
|
+
|
|
304
|
+
data_dir = make_sim_data_dir(
|
|
305
|
+
observations,
|
|
306
|
+
reward_df=reward_df,
|
|
307
|
+
obs_rewards=obs_rewards,
|
|
308
|
+
in_files=in_files,
|
|
309
|
+
sim_runner_kwargs=kwargs,
|
|
310
|
+
tags=tags,
|
|
311
|
+
label=label,
|
|
312
|
+
opsim_metadata=opsim_metadata,
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
resource_path = ResourcePath(data_dir.name, forceDirctory=True) # type: ignore
|
|
316
|
+
|
|
317
|
+
results = sim_results + (resource_path,)
|
|
318
|
+
return results
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def find_latest_prenight_sim_for_nights(
|
|
322
|
+
first_day_obs: str | None = None,
|
|
323
|
+
last_day_obs: str | None = None,
|
|
324
|
+
tags: tuple[str, ...] = ("ideal", "nominal"),
|
|
325
|
+
telescope: str = "simonyi",
|
|
326
|
+
max_simulation_age: int = 2,
|
|
327
|
+
get_prenight_index_kwargs: dict | None = None,
|
|
328
|
+
) -> dict:
|
|
329
|
+
"""Find the most recent prenight simulation that covers a night.
|
|
330
|
+
|
|
331
|
+
Parameters
|
|
332
|
+
----------
|
|
333
|
+
first_day_obs : `str` or `None`
|
|
334
|
+
The date of the evening for the first night for which to get
|
|
335
|
+
a simulation. If `None`, then the current date will be used.
|
|
336
|
+
last_day_obs : `str` or `None`
|
|
337
|
+
The date of the evening for the last night for which to get
|
|
338
|
+
a simulation. If `None`, then the current date will be used.
|
|
339
|
+
tags : `tuple[str]`
|
|
340
|
+
A tuple of tags to filter simulations by.
|
|
341
|
+
Defaults to ``('ideal', 'nominal')``.
|
|
342
|
+
telescope : `str`
|
|
343
|
+
The telescope to search for (simonyi or auxtel).
|
|
344
|
+
Defaults to simonyi.
|
|
345
|
+
max_simulation_age : `int`
|
|
346
|
+
The maximum age of simulations to consider, in days.
|
|
347
|
+
Simulations older than ``max_simulation_age`` will not be considered.
|
|
348
|
+
Defaults to 2.
|
|
349
|
+
|
|
350
|
+
Returns
|
|
351
|
+
-------
|
|
352
|
+
sim_metadata : `dict`
|
|
353
|
+
A dictionary with metadata for the simulation.
|
|
354
|
+
"""
|
|
355
|
+
if first_day_obs is None:
|
|
356
|
+
first_day_obs = datetime.now(ZoneInfo("Etc/GMT+12")).date().isoformat()
|
|
357
|
+
if last_day_obs is None:
|
|
358
|
+
last_day_obs = first_day_obs
|
|
359
|
+
|
|
360
|
+
if get_prenight_index_kwargs is None:
|
|
361
|
+
get_prenight_index_kwargs = {}
|
|
362
|
+
assert isinstance(get_prenight_index_kwargs, dict)
|
|
363
|
+
|
|
364
|
+
sims_for_first_night = get_prenight_index(first_day_obs, telescope, **get_prenight_index_kwargs)
|
|
365
|
+
if first_day_obs != last_day_obs:
|
|
366
|
+
sims_for_last_night = get_prenight_index(last_day_obs, telescope, **get_prenight_index_kwargs)
|
|
367
|
+
full_range_sims = set(sims_for_first_night.index) & set(sims_for_last_night.index)
|
|
368
|
+
else:
|
|
369
|
+
full_range_sims = set(sims_for_first_night.index)
|
|
370
|
+
|
|
371
|
+
result: dict = {}
|
|
372
|
+
if full_range_sims:
|
|
373
|
+
candidate_sims = sims_for_first_night.loc[tuple(full_range_sims), :]
|
|
374
|
+
maybe_result = select_latest_prenight_sim(candidate_sims, tags, max_simulation_age)
|
|
375
|
+
if maybe_result is not None:
|
|
376
|
+
assert isinstance(maybe_result, pd.Series)
|
|
377
|
+
result = maybe_result.to_dict()
|
|
378
|
+
|
|
379
|
+
return result
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
def fetch_sim_for_nights(
|
|
383
|
+
first_day_obs: str | None = None,
|
|
384
|
+
last_day_obs: str | None = None,
|
|
385
|
+
which_sim: ResourcePath | str | dict | None = None,
|
|
386
|
+
stackers: Sequence[BaseStacker] = (),
|
|
387
|
+
get_sim_data_kwargs: dict | None = None,
|
|
388
|
+
) -> pd.DataFrame | None:
|
|
389
|
+
"""Fetches visit metadata from an opsim database for specified nights.
|
|
390
|
+
|
|
391
|
+
Parameters
|
|
392
|
+
----------
|
|
393
|
+
first_day_obs : `str` or `None`
|
|
394
|
+
The date of the evening for the first night for which to get
|
|
395
|
+
a simulation. If `None`, then the current date will be used.
|
|
396
|
+
last_day_obs : `str` or `None`
|
|
397
|
+
The date of the evening for the last night for which to get
|
|
398
|
+
a simulation. If `None`, then the current date will be used.
|
|
399
|
+
which_sim : `ResourcePath` or `str` or `dict` on `None`
|
|
400
|
+
The ``resourcePath`` or URL of the opsim file from which to
|
|
401
|
+
load visits, or the arguments to
|
|
402
|
+
``find_latest_prenight_sim_for_nights``
|
|
403
|
+
to use to determine which simulation to load. ``None`` uses
|
|
404
|
+
default arguments to ``find_latest_prenight_sim_for_nights``.
|
|
405
|
+
Defaults to ``None``.
|
|
406
|
+
stackers : `Sequence[BaseStacker]`
|
|
407
|
+
A sequence of maf stackers to apply.
|
|
408
|
+
get_sim_data_kwargs : `dict`
|
|
409
|
+
Additional arguments to ``get_sim_data`` to use to load
|
|
410
|
+
the visits.
|
|
411
|
+
|
|
412
|
+
Returns
|
|
413
|
+
-------
|
|
414
|
+
visits : `pd.DataFrame`
|
|
415
|
+
A pandas DataFrame containing visit parameters.
|
|
416
|
+
"""
|
|
417
|
+
if first_day_obs is None:
|
|
418
|
+
first_day_obs = datetime.now(ZoneInfo("Etc/GMT+12")).date().isoformat()
|
|
419
|
+
if last_day_obs is None:
|
|
420
|
+
last_day_obs = first_day_obs
|
|
421
|
+
|
|
422
|
+
opsim_rp: ResourcePath | None = None
|
|
423
|
+
match which_sim:
|
|
424
|
+
case ResourcePath():
|
|
425
|
+
opsim_rp = which_sim
|
|
426
|
+
case str():
|
|
427
|
+
opsim_rp = ResourcePath(which_sim)
|
|
428
|
+
case dict():
|
|
429
|
+
this_sim = find_latest_prenight_sim_for_nights(first_day_obs, last_day_obs, **which_sim)
|
|
430
|
+
if len(this_sim) == 0:
|
|
431
|
+
raise ValueError("No matching simulations found")
|
|
432
|
+
visitseq_url = this_sim["visitseq_url"]
|
|
433
|
+
if visitseq_url is not None:
|
|
434
|
+
opsim_rp = ResourcePath(visitseq_url)
|
|
435
|
+
elif "opsim" in this_sim["files"]:
|
|
436
|
+
opsim_rp = ResourcePath(this_sim["files"]["opsim"])
|
|
437
|
+
else:
|
|
438
|
+
raise ValueError("No visits found")
|
|
439
|
+
case None:
|
|
440
|
+
this_sim = find_latest_prenight_sim_for_nights(first_day_obs, last_day_obs)
|
|
441
|
+
if len(this_sim) == 0:
|
|
442
|
+
raise ValueError("No matching simulations found")
|
|
443
|
+
visitseq_url = this_sim["visitseq_url"]
|
|
444
|
+
if visitseq_url is not None:
|
|
445
|
+
opsim_rp = ResourcePath(visitseq_url)
|
|
446
|
+
elif "opsim" in this_sim["files"]:
|
|
447
|
+
opsim_rp = ResourcePath(this_sim["files"]["opsim"])
|
|
448
|
+
else:
|
|
449
|
+
raise ValueError("Ne visits found")
|
|
450
|
+
case _:
|
|
451
|
+
raise NotImplementedError()
|
|
452
|
+
|
|
453
|
+
assert isinstance(opsim_rp, ResourcePath)
|
|
454
|
+
|
|
455
|
+
if len(stackers) == 0:
|
|
456
|
+
if isinstance(get_sim_data_kwargs, dict) and "stackers" in get_sim_data_kwargs:
|
|
457
|
+
stackers = get_sim_data_kwargs["stackers"]
|
|
458
|
+
else:
|
|
459
|
+
stackers = []
|
|
460
|
+
assert isinstance(stackers, list)
|
|
461
|
+
|
|
462
|
+
dayobsiso_requested = maf.DayObsISOStacker in [s.__class__ for s in stackers]
|
|
463
|
+
if not dayobsiso_requested:
|
|
464
|
+
# We want it to filter out dates that were not requested,
|
|
465
|
+
# so add it to the stacker even if it was not requested.
|
|
466
|
+
stackers.append(maf.DayObsISOStacker())
|
|
467
|
+
|
|
468
|
+
if opsim_rp.getExtension() in (".db", ".sqlite3"):
|
|
469
|
+
if get_sim_data_kwargs is None:
|
|
470
|
+
get_sim_data_kwargs = {}
|
|
471
|
+
assert isinstance(get_sim_data_kwargs, dict)
|
|
472
|
+
get_sim_data_kwargs["stackers"] = stackers
|
|
473
|
+
visits_recarray = get_sim_data(opsim_rp, **get_sim_data_kwargs)
|
|
474
|
+
visits = pd.DataFrame(visits_recarray)
|
|
475
|
+
else:
|
|
476
|
+
visits = get_visits(opsim_rp, stackers=stackers)
|
|
477
|
+
|
|
478
|
+
LOGGER.debug(f"Loaded {len(visits)} from {opsim_rp}")
|
|
479
|
+
on_requested_dates = (first_day_obs <= visits["day_obs_iso8601"]) & (
|
|
480
|
+
visits["day_obs_iso8601"] <= last_day_obs
|
|
481
|
+
)
|
|
482
|
+
visits = visits.loc[on_requested_dates, :]
|
|
483
|
+
# If it dayobsiso was not requested, do not return it.
|
|
484
|
+
if not dayobsiso_requested:
|
|
485
|
+
visits.drop(columns="day_obs_iso8601", inplace=True)
|
|
486
|
+
|
|
487
|
+
return visits
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
def fetch_obsloctap_visits(
|
|
491
|
+
day_obs: str | None = None,
|
|
492
|
+
nights: int = 2,
|
|
493
|
+
telescope: str = "simonyi",
|
|
494
|
+
columns: Sequence[str] = (
|
|
495
|
+
"observationStartMJD",
|
|
496
|
+
"fieldRA",
|
|
497
|
+
"fieldDec",
|
|
498
|
+
"rotSkyPos",
|
|
499
|
+
"band",
|
|
500
|
+
"visitExposureTime",
|
|
501
|
+
"night",
|
|
502
|
+
"target_name",
|
|
503
|
+
),
|
|
504
|
+
) -> pd.DataFrame | None:
|
|
505
|
+
"""Return visits from latest nominal prenight briefing simulation.
|
|
506
|
+
|
|
507
|
+
Parameters
|
|
508
|
+
----------
|
|
509
|
+
day_obs : `str`
|
|
510
|
+
The day_obs of the night, in YYYY-MM-DD format (e.g. 2025-03-26).
|
|
511
|
+
Default None will use the date of the next sunset.
|
|
512
|
+
nights : `int`
|
|
513
|
+
The number of nights of observations to return.
|
|
514
|
+
Defaults to 2.
|
|
515
|
+
telescope : `str`
|
|
516
|
+
The telescope to get visits for: "simonyi" or "auxtel".
|
|
517
|
+
Defaults to "simonyi".
|
|
518
|
+
colums : `Sequence`
|
|
519
|
+
A sequence of columns from the simulation to include.
|
|
520
|
+
|
|
521
|
+
Returns
|
|
522
|
+
-------
|
|
523
|
+
visits : `pd.DataFrame`
|
|
524
|
+
The visits from the prenight simulation.
|
|
525
|
+
"""
|
|
526
|
+
# Start with the first night that starts after the reference time,
|
|
527
|
+
# which is the current time by default.
|
|
528
|
+
# So, if the reference time is during a night, it starts with the
|
|
529
|
+
# following night.
|
|
530
|
+
night_bounds = pd.DataFrame(Almanac().sunsets)
|
|
531
|
+
current_mjd = Time.now().mjd
|
|
532
|
+
assert isinstance(current_mjd, float)
|
|
533
|
+
reference_mjd = (Time.now() if day_obs is None else Time(day_obs, format="iso", scale="utc")).mjd
|
|
534
|
+
assert isinstance(reference_mjd, float)
|
|
535
|
+
first_night = night_bounds.query(f"sunset > {reference_mjd}").night.min()
|
|
536
|
+
last_night = first_night + nights - 1
|
|
537
|
+
|
|
538
|
+
night_bounds.set_index("night", inplace=True)
|
|
539
|
+
start_mjd = night_bounds.loc[first_night, "sunset"]
|
|
540
|
+
assert isinstance(start_mjd, float)
|
|
541
|
+
end_mjd = night_bounds.loc[last_night, "sunrise"]
|
|
542
|
+
assert isinstance(end_mjd, float)
|
|
543
|
+
|
|
544
|
+
first_day_obs = Time(start_mjd - 0.5, format="mjd").iso[:10]
|
|
545
|
+
assert isinstance(first_day_obs, str)
|
|
546
|
+
last_day_obs = Time(end_mjd - 0.5, format="mjd").iso[:10]
|
|
547
|
+
assert isinstance(last_day_obs, str)
|
|
548
|
+
|
|
549
|
+
which_sim = {
|
|
550
|
+
"tags": ("ideal", "nominal"),
|
|
551
|
+
"telescope": telescope,
|
|
552
|
+
"max_simulation_age": int(np.ceil(current_mjd - reference_mjd)) + 1,
|
|
553
|
+
}
|
|
554
|
+
visits = fetch_sim_for_nights(first_day_obs, last_day_obs, which_sim=which_sim)
|
|
555
|
+
if visits is not None:
|
|
556
|
+
assert isinstance(visits, pd.DataFrame)
|
|
557
|
+
visits = visits.loc[:, list(columns)]
|
|
558
|
+
|
|
559
|
+
return visits
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
def fetch_sim_stats_for_night(
|
|
563
|
+
day_obs: str | int | None = None,
|
|
564
|
+
tags: tuple[str, ...] = ("ideal", "nominal"),
|
|
565
|
+
telescope: str = "simonyi",
|
|
566
|
+
max_simulation_age: int = 2,
|
|
567
|
+
host: Optional[str] = None,
|
|
568
|
+
user: Optional[str] = None,
|
|
569
|
+
database: Optional[str] = None,
|
|
570
|
+
schema: Optional[str] = None,
|
|
571
|
+
prenight_index_path: str | ResourcePath | None = None,
|
|
572
|
+
) -> dict:
|
|
573
|
+
"""Count the visits on a night in the latest nominal sim for a night.
|
|
574
|
+
|
|
575
|
+
Parameters
|
|
576
|
+
----------
|
|
577
|
+
day_obs : `str` or 'int' or `None`
|
|
578
|
+
Integer dayobs (int(YYYYMMDD)) or ISO string (``YYYY-MM-DD``)
|
|
579
|
+
or `None` (day_obs including the evening of yesterday in local time).
|
|
580
|
+
tags : `tuple[str]`
|
|
581
|
+
A tuple of tags to filter simulations by.
|
|
582
|
+
Defaults to ``('ideal', 'nominal')``.
|
|
583
|
+
telescope : `str`
|
|
584
|
+
The telescope to search for (simonyi or auxtel).
|
|
585
|
+
Defaults to simonyi.
|
|
586
|
+
max_simulation_age : `int`
|
|
587
|
+
The maximum age of simulations to consider, in days.
|
|
588
|
+
Simulations older than ``max_simulation_age`` will not be considered.
|
|
589
|
+
Defaults to 2.
|
|
590
|
+
host : `str` or `None`, optional
|
|
591
|
+
Database host address.
|
|
592
|
+
user : `str` or `None`, optional
|
|
593
|
+
Database user name.
|
|
594
|
+
database : `str` or `None`, optional
|
|
595
|
+
Database name.
|
|
596
|
+
schema : `str` or None, optional
|
|
597
|
+
The schema in the database to use.
|
|
598
|
+
prenight_index_path : `str` or `ResourcePath`, optional
|
|
599
|
+
Root path to the bucket files (used only if the database call fails).
|
|
600
|
+
|
|
601
|
+
Returns
|
|
602
|
+
-------
|
|
603
|
+
sim_stats : `dict`
|
|
604
|
+
A dict with statistics for the night. Returns an empty dict when
|
|
605
|
+
no statistics are availble.
|
|
606
|
+
"""
|
|
607
|
+
if day_obs is None:
|
|
608
|
+
day_obs = (date.today() - timedelta(days=1)).isoformat()
|
|
609
|
+
else:
|
|
610
|
+
day_obs = dayobs_to_date(day_obs).isoformat()
|
|
611
|
+
|
|
612
|
+
sim = find_latest_prenight_sim_for_nights(
|
|
613
|
+
day_obs,
|
|
614
|
+
tags=tags,
|
|
615
|
+
telescope=telescope,
|
|
616
|
+
max_simulation_age=max_simulation_age,
|
|
617
|
+
get_prenight_index_kwargs={
|
|
618
|
+
"host": host,
|
|
619
|
+
"user": user,
|
|
620
|
+
"database": database,
|
|
621
|
+
"schema": schema,
|
|
622
|
+
"prenight_index_path": prenight_index_path,
|
|
623
|
+
},
|
|
624
|
+
)
|
|
625
|
+
|
|
626
|
+
if "stats" in sim:
|
|
627
|
+
stats_maybe = sim["stats"]
|
|
628
|
+
else:
|
|
629
|
+
LOGGER.info(
|
|
630
|
+
f"Querying the metadata database (host {host}, user {user}, schema {schema})"
|
|
631
|
+
"for stats on {day_obs}"
|
|
632
|
+
)
|
|
633
|
+
vseq_metadata = VisitSequenceArchiveMetadata(
|
|
634
|
+
metadata_db_kwargs={"host": host, "user": user, "database": database}, metadata_db_schema=schema
|
|
635
|
+
)
|
|
636
|
+
sims_with_stats = vseq_metadata.sims_on_night_with_stats(
|
|
637
|
+
day_obs, tags=tags, telescope=telescope, max_simulation_age=max_simulation_age
|
|
638
|
+
).set_index("visitseq_uuid")
|
|
639
|
+
try:
|
|
640
|
+
stats_maybe = sims_with_stats.loc[sim["visitseq_uuid"], "stats"]
|
|
641
|
+
except KeyError:
|
|
642
|
+
stats_maybe = None
|
|
643
|
+
if stats_maybe is None:
|
|
644
|
+
LOGGER.info("Stats not found in metadata database.")
|
|
645
|
+
|
|
646
|
+
stats = cast(dict[str, Any], stats_maybe) if isinstance(stats_maybe, dict) else {}
|
|
647
|
+
|
|
648
|
+
if len(stats) == 0 and isinstance(sim["visitseq_url"], str):
|
|
649
|
+
# We still got nothin'.
|
|
650
|
+
# Get the visits themselves and compute the stats
|
|
651
|
+
# from them.
|
|
652
|
+
LOGGER.info("Computing stats from visits.")
|
|
653
|
+
visits = get_visits(sim["visitseq_url"])
|
|
654
|
+
columns = [c for c in visits.columns if is_numeric_dtype(visits[c])]
|
|
655
|
+
stats_df = compute_nightly_stats(visits, columns=tuple(columns))
|
|
656
|
+
stats_maybe = stats_df.set_index("value_name").to_dict(orient="index")
|
|
657
|
+
stats = cast(dict[str, Any], stats_maybe) if isinstance(stats_maybe, dict) else {}
|
|
658
|
+
|
|
659
|
+
# We need to report number of nominal visits.
|
|
660
|
+
# This is not a directly recorded statistic,
|
|
661
|
+
# but every statistic records the number of
|
|
662
|
+
# values from which its statitics were calculated,
|
|
663
|
+
# which is what we want.
|
|
664
|
+
# Go through the values we have, and get the first
|
|
665
|
+
# with counts reported.
|
|
666
|
+
if "nominal_visits" not in stats:
|
|
667
|
+
for value_name in stats.keys():
|
|
668
|
+
value_stats = stats[value_name]
|
|
669
|
+
if isinstance(value_stats, dict):
|
|
670
|
+
if "count" in stats[value_name]:
|
|
671
|
+
stats["nominal_visits"] = stats[value_name]["count"]
|
|
672
|
+
break
|
|
673
|
+
|
|
674
|
+
# If we still do not have a count of visits, get
|
|
675
|
+
# the actual visits and count them
|
|
676
|
+
if isinstance(sim["visitseq_url"], str):
|
|
677
|
+
visits = get_visits(sim["visitseq_url"])
|
|
678
|
+
stats["nominal_visits"] = len(visits)
|
|
679
|
+
|
|
680
|
+
return stats
|