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,255 @@
|
|
|
1
|
+
__all__ = [
|
|
2
|
+
"get_scheduler",
|
|
3
|
+
"save_scheduler",
|
|
4
|
+
"add_make_scheduler_snapshot_args",
|
|
5
|
+
"make_scheduler_snapshot_cli",
|
|
6
|
+
"get_scheduler_from_config",
|
|
7
|
+
"get_scheduler_instance_from_repo",
|
|
8
|
+
]
|
|
9
|
+
|
|
10
|
+
import argparse
|
|
11
|
+
import bz2
|
|
12
|
+
import gzip
|
|
13
|
+
import importlib.util
|
|
14
|
+
import logging
|
|
15
|
+
import lzma
|
|
16
|
+
import pickle
|
|
17
|
+
import sys
|
|
18
|
+
import types
|
|
19
|
+
import typing
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
from tempfile import TemporaryDirectory
|
|
22
|
+
|
|
23
|
+
import numpy as np
|
|
24
|
+
from git import Repo
|
|
25
|
+
from rubin_scheduler.scheduler.example import example_scheduler
|
|
26
|
+
from rubin_scheduler.scheduler.model_observatory import ModelObservatory
|
|
27
|
+
from rubin_scheduler.scheduler.schedulers.core_scheduler import CoreScheduler
|
|
28
|
+
from rubin_scheduler.scheduler.utils import SchemaConverter
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def get_scheduler_from_config(config_script_path: str | Path) -> typing.Tuple[int, CoreScheduler]:
|
|
32
|
+
"""Generate a CoreScheduler according to a configuration in a file.
|
|
33
|
+
|
|
34
|
+
Parameters
|
|
35
|
+
----------
|
|
36
|
+
config_script_path : `str`
|
|
37
|
+
The configuration script path
|
|
38
|
+
|
|
39
|
+
Returns
|
|
40
|
+
-------
|
|
41
|
+
nside : `int`
|
|
42
|
+
The nside.
|
|
43
|
+
scheduler : `CoreScheduler`
|
|
44
|
+
An instance of the Rubin Observatory FBS.
|
|
45
|
+
|
|
46
|
+
Raises
|
|
47
|
+
------
|
|
48
|
+
ValueError
|
|
49
|
+
If the config file is invalid, or has invalid content.
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
# Follow example from official python docs:
|
|
53
|
+
# https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly
|
|
54
|
+
# The T&S supplied files have code in a __name__ == 'config' conditional
|
|
55
|
+
# that we need to be executed, so we *must* name the module "config"
|
|
56
|
+
config_module_name: str = "config"
|
|
57
|
+
config_module_spec = importlib.util.spec_from_file_location(config_module_name, config_script_path)
|
|
58
|
+
if config_module_spec is None or config_module_spec.loader is None:
|
|
59
|
+
# Make type checking happy
|
|
60
|
+
raise ValueError(f"Cannot load config file {config_script_path}")
|
|
61
|
+
|
|
62
|
+
config_module: types.ModuleType = importlib.util.module_from_spec(config_module_spec)
|
|
63
|
+
sys.modules[config_module_name] = config_module
|
|
64
|
+
config_module_spec.loader.exec_module(config_module)
|
|
65
|
+
|
|
66
|
+
try:
|
|
67
|
+
scheduler: CoreScheduler = config_module.scheduler
|
|
68
|
+
nside: int = scheduler.nside
|
|
69
|
+
except NameError:
|
|
70
|
+
nside, scheduler = config_module.get_scheduler()
|
|
71
|
+
assert isinstance(nside, int)
|
|
72
|
+
assert isinstance(scheduler, CoreScheduler)
|
|
73
|
+
|
|
74
|
+
return nside, scheduler
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def get_scheduler_instance_from_repo(
|
|
78
|
+
config_repo: str,
|
|
79
|
+
config_script: str,
|
|
80
|
+
config_ref: str = "main",
|
|
81
|
+
) -> CoreScheduler:
|
|
82
|
+
"""Generate a CoreScheduler according to a configuration in git.
|
|
83
|
+
|
|
84
|
+
Parameters
|
|
85
|
+
----------
|
|
86
|
+
config_repo : `str`
|
|
87
|
+
The git repository with the configuration.
|
|
88
|
+
config_script : `str`
|
|
89
|
+
The configuration script path (relative to the repository root).
|
|
90
|
+
config_ref : `str`, optional
|
|
91
|
+
The branch of the repository to use, by default "main"
|
|
92
|
+
|
|
93
|
+
Returns
|
|
94
|
+
-------
|
|
95
|
+
scheduler : `CoreScheduler`
|
|
96
|
+
An instance of the Rubin Observatory FBS.
|
|
97
|
+
|
|
98
|
+
Raises
|
|
99
|
+
------
|
|
100
|
+
ValueError
|
|
101
|
+
If the config file is invalid, or has invalid content.
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
with TemporaryDirectory() as local_config_repo_parent:
|
|
105
|
+
repo: Repo = Repo.clone_from(config_repo, local_config_repo_parent)
|
|
106
|
+
repo.git.checkout(config_ref)
|
|
107
|
+
full_config_script_path: Path = Path(repo.working_dir).joinpath(config_script)
|
|
108
|
+
scheduler = get_scheduler_from_config(full_config_script_path)[1]
|
|
109
|
+
|
|
110
|
+
return scheduler
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def get_scheduler(
|
|
114
|
+
config_repo: str | None = None,
|
|
115
|
+
config_script: str | None = None,
|
|
116
|
+
config_ref: str = "main",
|
|
117
|
+
visits_db: str | None = None,
|
|
118
|
+
) -> CoreScheduler:
|
|
119
|
+
"""Generate a CoreScheduler according to a configuration.
|
|
120
|
+
|
|
121
|
+
Parameters
|
|
122
|
+
----------
|
|
123
|
+
config_repo : `str`
|
|
124
|
+
The git repository with the configuration.
|
|
125
|
+
config_script : `str`
|
|
126
|
+
The configuration script path (relative to the repository root).
|
|
127
|
+
config_ref : `str`, optional
|
|
128
|
+
The branch of the repository to use, by default "main"
|
|
129
|
+
visits_db : `str` or `None`
|
|
130
|
+
Database from which to load pre-existing visits
|
|
131
|
+
|
|
132
|
+
Returns
|
|
133
|
+
-------
|
|
134
|
+
scheduler : `CoreScheduler`
|
|
135
|
+
An instance of the Rubin Observatory FBS.
|
|
136
|
+
|
|
137
|
+
Raises
|
|
138
|
+
------
|
|
139
|
+
ValueError
|
|
140
|
+
If the config file is invalid, or has invalid content.
|
|
141
|
+
"""
|
|
142
|
+
if config_repo is not None and len(config_repo) > 0:
|
|
143
|
+
if config_script is None:
|
|
144
|
+
raise ValueError("If the config repo is set, the script must be as well.")
|
|
145
|
+
logging.info(
|
|
146
|
+
f"Instantiating scheduler form {config_script} on the {config_ref} branch of {config_repo}"
|
|
147
|
+
)
|
|
148
|
+
scheduler = get_scheduler_instance_from_repo(
|
|
149
|
+
config_repo=config_repo, config_script=config_script, config_ref=config_ref
|
|
150
|
+
)
|
|
151
|
+
elif config_script is not None:
|
|
152
|
+
logging.info(f"Reading scheduler from {config_script}")
|
|
153
|
+
scheduler = get_scheduler_from_config(config_script)[1]
|
|
154
|
+
else:
|
|
155
|
+
logging.info("Creating example scheduler")
|
|
156
|
+
example_scheduler_result = example_scheduler()
|
|
157
|
+
if isinstance(example_scheduler_result, CoreScheduler):
|
|
158
|
+
scheduler = example_scheduler_result
|
|
159
|
+
else:
|
|
160
|
+
# It might return a observatory, scheduler, observations tuple
|
|
161
|
+
# instead.
|
|
162
|
+
scheduler = example_scheduler_result[1]
|
|
163
|
+
|
|
164
|
+
if isinstance(visits_db, str) and len(visits_db) > 0:
|
|
165
|
+
logging.info(f"Adding visits from {visits_db}.")
|
|
166
|
+
obs: np.recarray = SchemaConverter().opsim2obs(visits_db)
|
|
167
|
+
if len(obs) > 0:
|
|
168
|
+
scheduler.add_observations_array(obs)
|
|
169
|
+
logging.info("Finished adding visits")
|
|
170
|
+
|
|
171
|
+
return scheduler
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def save_scheduler(scheduler: CoreScheduler, file_name: str) -> None:
|
|
175
|
+
"""Save an instances of the scheduler in a pickle file,
|
|
176
|
+
compressed according to its extension.
|
|
177
|
+
|
|
178
|
+
Parameters
|
|
179
|
+
----------
|
|
180
|
+
scheduler : `CoreScheduler`
|
|
181
|
+
The scheduler to save.
|
|
182
|
+
file_name : `str`
|
|
183
|
+
The file in which to save the schedulers.
|
|
184
|
+
"""
|
|
185
|
+
opener: typing.Callable = open
|
|
186
|
+
|
|
187
|
+
if file_name.endswith(".bz2"):
|
|
188
|
+
opener = bz2.open
|
|
189
|
+
elif file_name.endswith(".xz"):
|
|
190
|
+
opener = lzma.open
|
|
191
|
+
elif file_name.endswith(".gz"):
|
|
192
|
+
opener = gzip.open
|
|
193
|
+
|
|
194
|
+
with opener(file_name, "wb") as pio:
|
|
195
|
+
pickle.dump(scheduler, pio)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def add_make_scheduler_snapshot_args(parser: argparse.ArgumentParser) -> None:
|
|
199
|
+
"""Add arguments needed for saving a scheduler to an argument parser."""
|
|
200
|
+
parser.add_argument("--scheduler_fname", type=str, help="The file in which to save the scheduler.")
|
|
201
|
+
parser.add_argument(
|
|
202
|
+
"--repo", type=str, default=None, help="The repository from which to load the configuration."
|
|
203
|
+
)
|
|
204
|
+
parser.add_argument(
|
|
205
|
+
"--script", type=str, default=None, help="The path to the config script (relative to the repo root)."
|
|
206
|
+
)
|
|
207
|
+
parser.add_argument(
|
|
208
|
+
"--ref",
|
|
209
|
+
type=str,
|
|
210
|
+
default="main",
|
|
211
|
+
help="The git reference (tag/commit/branch) of the repo from which to get the script",
|
|
212
|
+
)
|
|
213
|
+
parser.add_argument(
|
|
214
|
+
"--visits", type=str, default="", help="Opsim database from which to load previous visits."
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def make_scheduler_snapshot_cli(cli_args: list = []) -> None:
|
|
219
|
+
parser = argparse.ArgumentParser(description="Create a scheduler pickle")
|
|
220
|
+
add_make_scheduler_snapshot_args(parser)
|
|
221
|
+
args: argparse.Namespace = parser.parse_args() if len(cli_args) == 0 else parser.parse_args(cli_args)
|
|
222
|
+
|
|
223
|
+
logging.basicConfig(
|
|
224
|
+
level=logging.DEBUG,
|
|
225
|
+
format="%(asctime)s:%(name)s:%(levelname)s:%(message)s",
|
|
226
|
+
datefmt="%Y-%m-%dT%H:%M:%S",
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
scheduler: CoreScheduler = get_scheduler(args.repo, args.script, args.ref, args.visits)
|
|
230
|
+
|
|
231
|
+
save_scheduler(scheduler, args.scheduler_fname)
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def make_ideal_model_observatory_cli(cli_args: list = []) -> None:
|
|
235
|
+
parser = argparse.ArgumentParser(description="Create an ideal model observatory pickle")
|
|
236
|
+
parser.add_argument("scheduler", type=str, help="Scheduler pickle file to read.")
|
|
237
|
+
parser.add_argument("model_observatory", type=str, help="Model observatory pickle file to write.")
|
|
238
|
+
args: argparse.Namespace = parser.parse_args() if len(cli_args) == 0 else parser.parse_args(cli_args)
|
|
239
|
+
|
|
240
|
+
with open(args.scheduler, "rb") as scheduler_io:
|
|
241
|
+
scheduler = pickle.load(scheduler_io)
|
|
242
|
+
|
|
243
|
+
observatory = ModelObservatory(
|
|
244
|
+
nside=scheduler.nside,
|
|
245
|
+
cloud_data="ideal",
|
|
246
|
+
seeing_data="ideal",
|
|
247
|
+
downtimes="ideal",
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
with open(args.model_observatory, "wb") as observatory_io:
|
|
251
|
+
pickle.dump(observatory, observatory_io)
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
if __name__ == "__main__":
|
|
255
|
+
make_scheduler_snapshot_cli()
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"""Tools for running the set of simulations used for a pre-night briefing."""
|
|
2
|
+
|
|
3
|
+
__all__ = ["AnomalousOverheadFunc", "run_prenight_sim_cli"]
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import logging
|
|
7
|
+
import pickle
|
|
8
|
+
import warnings
|
|
9
|
+
from datetime import date
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
import numpy as np
|
|
13
|
+
from matplotlib.pylab import Generator
|
|
14
|
+
from rubin_scheduler.scheduler import sim_runner
|
|
15
|
+
from rubin_scheduler.site_models import Almanac
|
|
16
|
+
|
|
17
|
+
from rubin_sim.sim_archive import make_sim_data_dir
|
|
18
|
+
|
|
19
|
+
from .util import dayobs_to_date
|
|
20
|
+
|
|
21
|
+
LOGGER = logging.getLogger(__name__)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class AnomalousOverheadFunc:
|
|
25
|
+
"""Callable to return random overhead.
|
|
26
|
+
|
|
27
|
+
Parameters
|
|
28
|
+
----------
|
|
29
|
+
seed : `int`
|
|
30
|
+
Random number seed.
|
|
31
|
+
slew_scale : `float`
|
|
32
|
+
The scale for the scatter in the slew offest (seconds).
|
|
33
|
+
visit_scale : `float`, optional
|
|
34
|
+
The scale for the scatter in the visit overhead offset (seconds).
|
|
35
|
+
Defaults to 0.0.
|
|
36
|
+
slew_loc : `float`, optional
|
|
37
|
+
The location of the scatter in the slew offest (seconds).
|
|
38
|
+
Defaults to 0.0.
|
|
39
|
+
visit_loc : `float`, optional
|
|
40
|
+
The location of the scatter in the visit offset (seconds).
|
|
41
|
+
Defaults to 0.0.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
def __init__(
|
|
45
|
+
self,
|
|
46
|
+
seed: int,
|
|
47
|
+
slew_scale: float,
|
|
48
|
+
visit_scale: float = 0.0,
|
|
49
|
+
slew_loc: float = 0.0,
|
|
50
|
+
visit_loc: float = 0.0,
|
|
51
|
+
) -> None:
|
|
52
|
+
self.rng: Generator = np.random.default_rng(seed)
|
|
53
|
+
self.visit_loc: float = visit_loc
|
|
54
|
+
self.visit_scale: float = visit_scale
|
|
55
|
+
self.slew_loc: float = slew_loc
|
|
56
|
+
self.slew_scale: float = slew_scale
|
|
57
|
+
|
|
58
|
+
def __call__(self, visittime: float, slewtime: float) -> float:
|
|
59
|
+
"""Return a randomized offset for the visit overhead.
|
|
60
|
+
|
|
61
|
+
Parameters
|
|
62
|
+
----------
|
|
63
|
+
visittime : `float`
|
|
64
|
+
The visit time (seconds).
|
|
65
|
+
slewtime : `float`
|
|
66
|
+
The slew time (seconds).
|
|
67
|
+
|
|
68
|
+
Returns
|
|
69
|
+
-------
|
|
70
|
+
offset: `float`
|
|
71
|
+
Random offset (seconds).
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
slew_overhead: float = slewtime * self.rng.normal(self.slew_loc, self.slew_scale)
|
|
75
|
+
|
|
76
|
+
# Slew might be faster that expected, but it will never take negative
|
|
77
|
+
# time.
|
|
78
|
+
if (slewtime + slew_overhead) < 0:
|
|
79
|
+
slew_overhead = 0.0
|
|
80
|
+
|
|
81
|
+
visit_overhead: float = visittime * self.rng.normal(self.slew_loc, self.slew_scale)
|
|
82
|
+
# There might be anomalous overhead that makes visits take longer,
|
|
83
|
+
# but faster is unlikely.
|
|
84
|
+
if visit_overhead < 0:
|
|
85
|
+
visit_overhead = 0.0
|
|
86
|
+
|
|
87
|
+
return slew_overhead + visit_overhead
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def compute_sim_start_and_end(day_obs: int, sim_nights: int, delay: float = 0) -> tuple[float, float]:
|
|
91
|
+
"""Compute simulation start and end time for a prenight simulation.
|
|
92
|
+
|
|
93
|
+
Parameters
|
|
94
|
+
----------
|
|
95
|
+
day_obs: `int`
|
|
96
|
+
The starting dayobs as YYYYMMDD.
|
|
97
|
+
sim_nights: `int`
|
|
98
|
+
The number of nights to simulate
|
|
99
|
+
delay: `float`
|
|
100
|
+
A delayed start, in minutes.
|
|
101
|
+
|
|
102
|
+
Return
|
|
103
|
+
------
|
|
104
|
+
sim_start_mjd, sim_duration : `tuple`
|
|
105
|
+
The starting MJD and simulation duration in days.
|
|
106
|
+
"""
|
|
107
|
+
# Find the start of observing for the specified day_obs.
|
|
108
|
+
# Almanac.get_sunset_info does not use day_obs, so
|
|
109
|
+
# translate to DJD, Dublin Julian Date.
|
|
110
|
+
# Like plain Julian Date, DJD rolls over at the
|
|
111
|
+
# same time as day_obs, but unlike JD, the year
|
|
112
|
+
# of the epoch works with python's datetime.date.
|
|
113
|
+
# Note that MJD - DJD = 15019.5
|
|
114
|
+
# and has epoch 1899-12-31T12:00:00.
|
|
115
|
+
sunsets = Almanac().sunsets
|
|
116
|
+
djd_mjd_offset = 15019.5
|
|
117
|
+
djd0 = date(1899, 12, 31)
|
|
118
|
+
|
|
119
|
+
night0_djd = int(np.floor(sunsets["sunset"][0] - djd_mjd_offset))
|
|
120
|
+
day_obs_date = dayobs_to_date(day_obs)
|
|
121
|
+
day_obs_djd = (day_obs_date - djd0).days
|
|
122
|
+
day_obs_start_night = day_obs_djd - night0_djd
|
|
123
|
+
sim_start_mjd = sunsets["sun_n12_setting"][day_obs_start_night] + delay / (24 * 60.0)
|
|
124
|
+
day_obs_end_night = day_obs_start_night + sim_nights - 1
|
|
125
|
+
sim_end_mjd = sunsets["sunrise"][day_obs_end_night]
|
|
126
|
+
sim_duration = sim_end_mjd - sim_start_mjd
|
|
127
|
+
assert np.ceil(sim_duration) == sim_nights
|
|
128
|
+
return sim_start_mjd, sim_duration
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def run_prenight_sim_cli(cli_args: list = []) -> int:
|
|
132
|
+
parser = argparse.ArgumentParser(description="Run an SV simulation.")
|
|
133
|
+
parser.add_argument("scheduler", type=str, help="scheduler pickle file.")
|
|
134
|
+
parser.add_argument("observatory", type=str, help="model observatory pickle file.")
|
|
135
|
+
parser.add_argument("day_obs", type=int, help="start day obs.")
|
|
136
|
+
parser.add_argument("sim_nights", type=int, help="number of nights to run.")
|
|
137
|
+
parser.add_argument("--keep_rewards", action="store_true", help="Compute rewards data.")
|
|
138
|
+
parser.add_argument("--telescope", type=str, default="simonyi", help="The telescope simulated.")
|
|
139
|
+
parser.add_argument("--label", type=str, default="", help="The tags on the simulation.")
|
|
140
|
+
parser.add_argument("--delay", type=float, default=0.0, help="Minutes after nominal to start.")
|
|
141
|
+
parser.add_argument("--anom_overhead_scale", type=float, default=0.0, help="scale of scatter in the slew")
|
|
142
|
+
parser.add_argument(
|
|
143
|
+
"--anom_overhead_seed",
|
|
144
|
+
type=int,
|
|
145
|
+
default=1,
|
|
146
|
+
help="random number seed for anomalous scatter in overhead",
|
|
147
|
+
)
|
|
148
|
+
parser.add_argument("--tags", type=str, default=[], nargs="*", help="The tags on the simulation.")
|
|
149
|
+
parser.add_argument("--results", type=str, default="", help="Results directory.")
|
|
150
|
+
args = parser.parse_args() if len(cli_args) == 0 else parser.parse_args(cli_args)
|
|
151
|
+
day_obs = args.day_obs
|
|
152
|
+
sim_nights = args.sim_nights
|
|
153
|
+
keep_rewards = args.keep_rewards
|
|
154
|
+
tags = args.tags
|
|
155
|
+
label = args.label
|
|
156
|
+
telescope = args.telescope
|
|
157
|
+
delay = args.delay
|
|
158
|
+
anom_overhead_scale = args.anom_overhead_scale
|
|
159
|
+
anom_overhead_seed = args.anom_overhead_seed
|
|
160
|
+
results_dir = args.results if len(args.results) > 0 else None
|
|
161
|
+
|
|
162
|
+
with open(args.scheduler, "rb") as scheduler_io:
|
|
163
|
+
scheduler = pickle.load(scheduler_io)
|
|
164
|
+
|
|
165
|
+
with open(args.observatory, "rb") as observatory_io:
|
|
166
|
+
observatory = pickle.load(observatory_io)
|
|
167
|
+
|
|
168
|
+
if anom_overhead_scale > 0:
|
|
169
|
+
anomalous_overhead_func = AnomalousOverheadFunc(anom_overhead_seed, anom_overhead_scale)
|
|
170
|
+
else:
|
|
171
|
+
anomalous_overhead_func = None
|
|
172
|
+
|
|
173
|
+
if keep_rewards:
|
|
174
|
+
scheduler.keep_rewards = keep_rewards
|
|
175
|
+
|
|
176
|
+
sim_start_mjd, sim_duration = compute_sim_start_and_end(day_obs, sim_nights, delay)
|
|
177
|
+
observatory.mjd = sim_start_mjd
|
|
178
|
+
|
|
179
|
+
LOGGER.info("Starting simulation")
|
|
180
|
+
with warnings.catch_warnings():
|
|
181
|
+
warnings.simplefilter("ignore", RuntimeWarning)
|
|
182
|
+
results = sim_runner(
|
|
183
|
+
observatory,
|
|
184
|
+
scheduler,
|
|
185
|
+
sim_start_mjd=sim_start_mjd,
|
|
186
|
+
sim_duration=sim_duration,
|
|
187
|
+
record_rewards=keep_rewards,
|
|
188
|
+
verbose=True,
|
|
189
|
+
anomalous_overhead_func=anomalous_overhead_func,
|
|
190
|
+
)
|
|
191
|
+
observatory, scheduler, obs = results[:3]
|
|
192
|
+
rewards, obs_rewards = (None, None) if len(results) < 5 else results[3:5]
|
|
193
|
+
LOGGER.info("Simulation complete.")
|
|
194
|
+
|
|
195
|
+
LOGGER.info("Writing simulation results")
|
|
196
|
+
data_path = make_sim_data_dir(
|
|
197
|
+
obs,
|
|
198
|
+
rewards,
|
|
199
|
+
obs_rewards,
|
|
200
|
+
in_files={"scheduler": args.scheduler, "observatory": args.observatory},
|
|
201
|
+
tags=tags,
|
|
202
|
+
label=label,
|
|
203
|
+
opsim_metadata={"telescope": telescope},
|
|
204
|
+
data_path=results_dir,
|
|
205
|
+
)
|
|
206
|
+
output_dirname: str = "Unknown"
|
|
207
|
+
if isinstance(data_path, Path):
|
|
208
|
+
assert isinstance(data_path, Path)
|
|
209
|
+
output_dirname = data_path.name
|
|
210
|
+
else:
|
|
211
|
+
assert isinstance(data_path, str)
|
|
212
|
+
output_dirname = data_path
|
|
213
|
+
|
|
214
|
+
LOGGER.info(f"Wrote results in directory: {output_dirname}")
|
|
215
|
+
|
|
216
|
+
return 0
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
__all__ = ["get_prenight_index", "select_latest_prenight_sim"]
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import os
|
|
5
|
+
from datetime import date
|
|
6
|
+
|
|
7
|
+
import pandas as pd
|
|
8
|
+
from lsst.resources import ResourcePath
|
|
9
|
+
|
|
10
|
+
if "PRENIGHT_INDEX_URL" in os.environ:
|
|
11
|
+
PRENIGHT_INDEX_URL = os.environ["PRENIGHT_INDEX_URL"]
|
|
12
|
+
else:
|
|
13
|
+
from rubin_sim.sim_archive.vseqarchive import PRENIGHT_INDEX_URL
|
|
14
|
+
|
|
15
|
+
from rubin_sim.sim_archive.vseqmetadata import VisitSequenceArchiveMetadata
|
|
16
|
+
|
|
17
|
+
from .util import dayobs_to_date
|
|
18
|
+
|
|
19
|
+
MAX_AGE = 365
|
|
20
|
+
LOGGER = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def get_prenight_index_from_database(
|
|
24
|
+
day_obs: str | int | date,
|
|
25
|
+
telescope: str = "simonyi",
|
|
26
|
+
schema: str | None = None,
|
|
27
|
+
host: str | None = None,
|
|
28
|
+
user: str | None = None,
|
|
29
|
+
database: str | None = None,
|
|
30
|
+
) -> pd.DataFrame:
|
|
31
|
+
"""
|
|
32
|
+
Retrieve the pre‑night observation index for a given night from the
|
|
33
|
+
LSST SIM Archive.
|
|
34
|
+
|
|
35
|
+
Parameters
|
|
36
|
+
----------
|
|
37
|
+
day_obs : `str` or `int` or `date`
|
|
38
|
+
The night for which to fetch the index. Accepts a date string,
|
|
39
|
+
YYYYMMDD encoded into an integer, or a :class:`datetime.date`
|
|
40
|
+
telescope : `str`, optional
|
|
41
|
+
Telescope name (default ``"simonyi"``). Passed directly to
|
|
42
|
+
:class:`~rubin_sim.sim_archive.vseqmetadata.VisitSequenceArchiveMetadata`.
|
|
43
|
+
schema : `str` or `None`, optional
|
|
44
|
+
Optional database schema name.
|
|
45
|
+
host : `str` or `None`, optional
|
|
46
|
+
Database host address.
|
|
47
|
+
user : `str` or `None`, optional
|
|
48
|
+
Database user name.
|
|
49
|
+
database : `str` or `None`, optional
|
|
50
|
+
Database name.
|
|
51
|
+
|
|
52
|
+
Returns
|
|
53
|
+
-------
|
|
54
|
+
prenights: `pandas.DataFrame`
|
|
55
|
+
A DataFrame indexed by ``visitseq_uuid`` containing all pre‑night
|
|
56
|
+
entries for the requested night. Columns mirror those returned
|
|
57
|
+
by the underlying `sims_on_nights` call.
|
|
58
|
+
|
|
59
|
+
Notes
|
|
60
|
+
-----
|
|
61
|
+
* The function uses a hard‑coded maximum simulation age of
|
|
62
|
+
:data:`MAX_AGE` (365 days) to limit the search.
|
|
63
|
+
* If any of ``host``, ``user`` or ``database`` are supplied, they
|
|
64
|
+
override the defaults in the ``metadata_dsn`` dictionary passed to
|
|
65
|
+
:class:`~rubin_sim.sim_archive.vseqmetadata.VisitSequenceArchiveMetadata`.
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
day_obs_date = dayobs_to_date(day_obs)
|
|
69
|
+
assert isinstance(day_obs_date, date)
|
|
70
|
+
|
|
71
|
+
metadata_dsn = {}
|
|
72
|
+
if host is not None:
|
|
73
|
+
metadata_dsn["host"] = host
|
|
74
|
+
if user is not None:
|
|
75
|
+
metadata_dsn["user"] = user
|
|
76
|
+
if database is not None:
|
|
77
|
+
metadata_dsn["database"] = database
|
|
78
|
+
|
|
79
|
+
visit_seq_archive_metadata = VisitSequenceArchiveMetadata(metadata_dsn, schema)
|
|
80
|
+
prenights = visit_seq_archive_metadata.sims_on_nights(
|
|
81
|
+
day_obs_date, day_obs_date, tags=["prenight"], telescope=telescope, max_simulation_age=MAX_AGE
|
|
82
|
+
).set_index("visitseq_uuid")
|
|
83
|
+
LOGGER.info(f"Got metadata on {len(prenights)} simulations from database")
|
|
84
|
+
return prenights
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def get_prenight_index_from_bucket(
|
|
88
|
+
day_obs: str | int | date,
|
|
89
|
+
telescope: str = "simonyi",
|
|
90
|
+
prenight_index_path: str | ResourcePath = PRENIGHT_INDEX_URL,
|
|
91
|
+
) -> pd.DataFrame:
|
|
92
|
+
"""
|
|
93
|
+
Load the pre‑night observation index for a given night from a remote
|
|
94
|
+
bucket.
|
|
95
|
+
|
|
96
|
+
Parameters
|
|
97
|
+
----------
|
|
98
|
+
day_obs : `str` or `int` or `date`
|
|
99
|
+
The night for which to fetch the index. Accepts a date string,
|
|
100
|
+
YYYYMMDD encoded into an integer, a ``datetime.date``
|
|
101
|
+
telescope : `str`, optional
|
|
102
|
+
Telescope name (default ``"simonyi"``).
|
|
103
|
+
prenight_index_path : `str` or `ResourcePath`, optional
|
|
104
|
+
The root path where the pre‑night index
|
|
105
|
+
JSON files are stored. It can be a string URL or a
|
|
106
|
+
``ResourcePath`` instance.
|
|
107
|
+
|
|
108
|
+
Returns
|
|
109
|
+
-------
|
|
110
|
+
prenights : `pandas.DataFrame`
|
|
111
|
+
A DataFrame indexed by the JSON key (``visitseq_uuid``) containing
|
|
112
|
+
all pre‑night entries for the requested night. The columns match
|
|
113
|
+
those stored in the JSON file.
|
|
114
|
+
"""
|
|
115
|
+
day_obs_date = dayobs_to_date(day_obs)
|
|
116
|
+
assert isinstance(day_obs_date, date)
|
|
117
|
+
|
|
118
|
+
prenight_index_path = ResourcePath(prenight_index_path, forceDirectory=True)
|
|
119
|
+
assert isinstance(prenight_index_path, ResourcePath)
|
|
120
|
+
|
|
121
|
+
year = day_obs_date.year
|
|
122
|
+
month = day_obs_date.month
|
|
123
|
+
isodate = day_obs_date.isoformat()
|
|
124
|
+
|
|
125
|
+
prenight_index_resource_path = (
|
|
126
|
+
prenight_index_path.join(telescope)
|
|
127
|
+
.join(str(year))
|
|
128
|
+
.join(str(month))
|
|
129
|
+
.join(f"{telescope}_prenights_for_{isodate}.json")
|
|
130
|
+
)
|
|
131
|
+
with prenight_index_resource_path.as_local() as local_resource_path:
|
|
132
|
+
prenights = pd.read_json(local_resource_path.ospath, orient="index")
|
|
133
|
+
|
|
134
|
+
return prenights
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def get_prenight_index(
|
|
138
|
+
day_obs: str | int | date,
|
|
139
|
+
telescope: str = "simonyi",
|
|
140
|
+
schema: str | None = None,
|
|
141
|
+
host: str | None = None,
|
|
142
|
+
user: str | None = None,
|
|
143
|
+
database: str | None = None,
|
|
144
|
+
prenight_index_path: str | ResourcePath | None = None,
|
|
145
|
+
) -> pd.DataFrame:
|
|
146
|
+
"""Retrieve the pre‑night observation index for a given night.
|
|
147
|
+
|
|
148
|
+
Parameters
|
|
149
|
+
----------
|
|
150
|
+
day_obs : `str` or `int` or `date`
|
|
151
|
+
Night for which to fetch the index.
|
|
152
|
+
telescope : `str`
|
|
153
|
+
Telescope name (default ``simonyi``).
|
|
154
|
+
schema : `str` or `None`, optional
|
|
155
|
+
Optional database schema name.
|
|
156
|
+
host : `str` or `None`, optional
|
|
157
|
+
Database host address.
|
|
158
|
+
user : `str` or `None`, optional
|
|
159
|
+
Database user name.
|
|
160
|
+
database : `str` or `None`, optional
|
|
161
|
+
Database name.
|
|
162
|
+
prenight_index_path : `str` or `ResourcePath`, optional
|
|
163
|
+
Root path to the bucket files (used only if the database call fails).
|
|
164
|
+
|
|
165
|
+
Returns
|
|
166
|
+
-------
|
|
167
|
+
prenights: `pd.DataFrame`
|
|
168
|
+
Pre‑night index indexed by ``visitseq_uuid``.
|
|
169
|
+
"""
|
|
170
|
+
try:
|
|
171
|
+
# Try the database first
|
|
172
|
+
prenights = get_prenight_index_from_database(day_obs, telescope, schema, host, user, database)
|
|
173
|
+
except Exception:
|
|
174
|
+
# Fall back to the bucket
|
|
175
|
+
LOGGER.info("Database not accessible, falling back on the index in the S3 bucket.")
|
|
176
|
+
if prenight_index_path is None:
|
|
177
|
+
prenight_index_path = PRENIGHT_INDEX_URL
|
|
178
|
+
try:
|
|
179
|
+
prenights = get_prenight_index_from_bucket(day_obs, telescope, prenight_index_path)
|
|
180
|
+
except FileNotFoundError:
|
|
181
|
+
prenights = pd.DataFrame()
|
|
182
|
+
|
|
183
|
+
return prenights
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def select_latest_prenight_sim(
|
|
187
|
+
prenights: pd.DataFrame,
|
|
188
|
+
tags: tuple[str, ...] = ("ideal", "nominal"),
|
|
189
|
+
max_simulation_age: int = 2,
|
|
190
|
+
) -> dict | None:
|
|
191
|
+
"""Select the best prenight simulation from a DataFrame.
|
|
192
|
+
|
|
193
|
+
Parameters
|
|
194
|
+
----------
|
|
195
|
+
prenights: `pd.DataFrame`
|
|
196
|
+
The table of prenights from which to select.
|
|
197
|
+
tags : `tuple` [`str`]
|
|
198
|
+
A tuple of tags to filter simulations by.
|
|
199
|
+
Defaults to ``('ideal', 'nominal')``.
|
|
200
|
+
max_simulation_age : `int`
|
|
201
|
+
The maximum age of simulations to consider, in days.
|
|
202
|
+
Simulations older than ``max_simulation_age`` will not be considered.
|
|
203
|
+
Defaults to 2.
|
|
204
|
+
|
|
205
|
+
Returns
|
|
206
|
+
-------
|
|
207
|
+
best_sim : `dict` or `None`
|
|
208
|
+
A dictionary with metadata for the simulation.
|
|
209
|
+
"""
|
|
210
|
+
best_sim = None
|
|
211
|
+
for _, sim in prenights.reset_index().iterrows():
|
|
212
|
+
if not set(tags).issubset(sim["tags"]):
|
|
213
|
+
continue
|
|
214
|
+
if best_sim is not None:
|
|
215
|
+
if sim["creation_time"] < best_sim["creation_time"]:
|
|
216
|
+
continue
|
|
217
|
+
|
|
218
|
+
age = (pd.Timestamp.now(tz="UTC") - sim["creation_time"]).days
|
|
219
|
+
if age > max_simulation_age:
|
|
220
|
+
continue
|
|
221
|
+
|
|
222
|
+
best_sim = sim
|
|
223
|
+
|
|
224
|
+
if best_sim is not None:
|
|
225
|
+
LOGGER.info(f"Most recent simulation meeting requested criteria is {best_sim['visitseq_url']}.")
|
|
226
|
+
else:
|
|
227
|
+
LOGGER.debug("No simulations met the requested criteria.")
|
|
228
|
+
|
|
229
|
+
return best_sim
|