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,231 @@
|
|
|
1
|
+
__all__ = ("ChebyValues",)
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import pandas as pd
|
|
7
|
+
|
|
8
|
+
from .chebyshev_utils import chebeval
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ChebyValues:
|
|
12
|
+
"""Calculates positions, velocities, deltas, vmags and elongations,
|
|
13
|
+
given a series of coefficients generated by ChebyFits.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(self):
|
|
17
|
+
self.coeffs = {}
|
|
18
|
+
self.coeff_keys = [
|
|
19
|
+
"obj_id",
|
|
20
|
+
"t_start",
|
|
21
|
+
"t_end",
|
|
22
|
+
"ra",
|
|
23
|
+
"dec",
|
|
24
|
+
"geo_dist",
|
|
25
|
+
"vmag",
|
|
26
|
+
"elongation",
|
|
27
|
+
]
|
|
28
|
+
self.ephemeris_keys = [
|
|
29
|
+
"ra",
|
|
30
|
+
"dradt",
|
|
31
|
+
"dec",
|
|
32
|
+
"ddecdt",
|
|
33
|
+
"geo_dist",
|
|
34
|
+
"vmag",
|
|
35
|
+
"elongation",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
def set_coefficients(self, cheby_fits):
|
|
39
|
+
"""Set coefficients using a ChebyFits object.
|
|
40
|
+
(which contains a dictionary of obj_id, t_start, t_end, ra,
|
|
41
|
+
dec, delta, vmag, and elongation lists).
|
|
42
|
+
|
|
43
|
+
Parameters
|
|
44
|
+
----------
|
|
45
|
+
cheby_fits : `rubin_sim.movingObjects.chebyFits`
|
|
46
|
+
ChebyFits object, with attribute 'coeffs' -
|
|
47
|
+
a dictionary of lists of coefficients.
|
|
48
|
+
"""
|
|
49
|
+
self.coeffs = cheby_fits.coeffs
|
|
50
|
+
# Convert list of coefficients into numpy arrays.
|
|
51
|
+
for k in self.coeffs:
|
|
52
|
+
self.coeffs[k] = np.array(self.coeffs[k])
|
|
53
|
+
# Check that expected values were received.
|
|
54
|
+
missing_keys = set(self.coeff_keys) - set(self.coeffs)
|
|
55
|
+
if len(missing_keys) > 0:
|
|
56
|
+
raise ValueError("Expected to find key(s) %s in coefficients." % " ".join(list[missing_keys]))
|
|
57
|
+
self.coeffs["meanRA"] = self.coeffs["ra"].swapaxes(0, 1)[0]
|
|
58
|
+
self.coeffs["meanDec"] = self.coeffs["dec"].swapaxes(0, 1)[0]
|
|
59
|
+
|
|
60
|
+
def read_coefficients(self, cheby_fits_file):
|
|
61
|
+
"""Read coefficients from output file written by ChebyFits.
|
|
62
|
+
|
|
63
|
+
Parameters
|
|
64
|
+
----------
|
|
65
|
+
cheby_fits_file : `str`
|
|
66
|
+
The filename of the coefficients file.
|
|
67
|
+
"""
|
|
68
|
+
if not os.path.isfile(cheby_fits_file):
|
|
69
|
+
raise IOError("Could not find cheby_fits_file at %s" % (cheby_fits_file))
|
|
70
|
+
# Read the coefficients file.
|
|
71
|
+
coeffs = pd.read_table(cheby_fits_file, sep=r"\s+")
|
|
72
|
+
# The header line provides information on the number of
|
|
73
|
+
# coefficients for each parameter.
|
|
74
|
+
datacols = coeffs.columns.values
|
|
75
|
+
cols = {}
|
|
76
|
+
coeff_cols = ["ra", "dec", "geo_dist", "vmag", "elongation"]
|
|
77
|
+
for k in coeff_cols:
|
|
78
|
+
cols[k] = [x for x in datacols if x.startswith(k)]
|
|
79
|
+
# Translate dataframe to dictionary of numpy arrays
|
|
80
|
+
# while consolidating RA/Dec/Delta/Vmag/Elongation coeffs.
|
|
81
|
+
self.coeffs["obj_id"] = coeffs.obj_id.values
|
|
82
|
+
self.coeffs["t_start"] = coeffs.t_start.values
|
|
83
|
+
self.coeffs["t_end"] = coeffs.t_end.values
|
|
84
|
+
for k in coeff_cols:
|
|
85
|
+
self.coeffs[k] = np.empty([len(cols[k]), len(coeffs)], float)
|
|
86
|
+
for i in range(len(cols[k])):
|
|
87
|
+
self.coeffs[k][i] = coeffs["%s_%d" % (k, i)].values
|
|
88
|
+
# Add the mean RA and Dec columns
|
|
89
|
+
# (before swapping the coefficients axes).
|
|
90
|
+
self.coeffs["meanRA"] = self.coeffs["ra"][0]
|
|
91
|
+
self.coeffs["meanDec"] = self.coeffs["dec"][0]
|
|
92
|
+
# Swap the coefficient axes so that they are [segment, coeff].
|
|
93
|
+
for k in coeff_cols:
|
|
94
|
+
self.coeffs[k] = self.coeffs[k].swapaxes(0, 1)
|
|
95
|
+
|
|
96
|
+
def _eval_segment(self, segment_idx, times, subset_segments=None, mask=True):
|
|
97
|
+
"""Evaluate the ra/dec/delta/vmag/elongation values for a
|
|
98
|
+
given segment at a series of times.
|
|
99
|
+
|
|
100
|
+
Parameters
|
|
101
|
+
----------
|
|
102
|
+
segment_idx : `int`
|
|
103
|
+
The index in (each of) self.coeffs for the segment.
|
|
104
|
+
e.g. the first segment, for each object.
|
|
105
|
+
times : `np.ndarray`
|
|
106
|
+
The times at which to evaluate the segment.
|
|
107
|
+
subset_segments : `np.ndarray`, optional
|
|
108
|
+
Optionally specify a subset of the total segment indexes.
|
|
109
|
+
This lets you pick out particular obj_ids.
|
|
110
|
+
mask : `bool`, optional
|
|
111
|
+
If True, returns NaNs for values outside the range of times
|
|
112
|
+
in the segment.
|
|
113
|
+
If False, extrapolates segment for times outside the
|
|
114
|
+
segment time range.
|
|
115
|
+
|
|
116
|
+
Returns
|
|
117
|
+
-------
|
|
118
|
+
ephemeris : `dict`
|
|
119
|
+
Dictionary of RA, Dec, delta, vmag, and elongation values for
|
|
120
|
+
the segment indicated, at the time indicated.
|
|
121
|
+
"""
|
|
122
|
+
if subset_segments is None:
|
|
123
|
+
subset_segments = np.ones(len(self.coeffs["obj_id"]), dtype=bool)
|
|
124
|
+
t_start = self.coeffs["t_start"][subset_segments][segment_idx]
|
|
125
|
+
t_end = self.coeffs["t_end"][subset_segments][segment_idx]
|
|
126
|
+
t_scaled = times - t_start
|
|
127
|
+
t_interval = np.array([t_start, t_end]) - t_start
|
|
128
|
+
# Evaluate RA/Dec/Delta/Vmag/elongation.
|
|
129
|
+
ephemeris = {}
|
|
130
|
+
ephemeris["ra"], ephemeris["dradt"] = chebeval(
|
|
131
|
+
t_scaled,
|
|
132
|
+
self.coeffs["ra"][subset_segments][segment_idx],
|
|
133
|
+
interval=t_interval,
|
|
134
|
+
do_velocity=True,
|
|
135
|
+
mask=mask,
|
|
136
|
+
)
|
|
137
|
+
ephemeris["dec"], ephemeris["ddecdt"] = chebeval(
|
|
138
|
+
t_scaled,
|
|
139
|
+
self.coeffs["dec"][subset_segments][segment_idx],
|
|
140
|
+
interval=t_interval,
|
|
141
|
+
do_velocity=True,
|
|
142
|
+
mask=mask,
|
|
143
|
+
)
|
|
144
|
+
ephemeris["dradt"] = ephemeris["dradt"] * np.cos(np.radians(ephemeris["dec"]))
|
|
145
|
+
for k in ("geo_dist", "vmag", "elongation"):
|
|
146
|
+
ephemeris[k], _ = chebeval(
|
|
147
|
+
t_scaled,
|
|
148
|
+
self.coeffs[k][subset_segments][segment_idx],
|
|
149
|
+
interval=t_interval,
|
|
150
|
+
do_velocity=False,
|
|
151
|
+
mask=mask,
|
|
152
|
+
)
|
|
153
|
+
return ephemeris
|
|
154
|
+
|
|
155
|
+
def get_ephemerides(self, times, obj_ids=None, extrapolate=False):
|
|
156
|
+
"""Find the ephemeris information for 'obj_ids' at 'time'.
|
|
157
|
+
|
|
158
|
+
Implicit in how this is currently written is that the segments
|
|
159
|
+
are all expected to cover the same start/end time range across
|
|
160
|
+
all objects.
|
|
161
|
+
They do not have to have the same segment length for all objects.
|
|
162
|
+
|
|
163
|
+
Parameters
|
|
164
|
+
----------
|
|
165
|
+
times : `float` or `np.ndarray`
|
|
166
|
+
The time to calculate ephemeris positions.
|
|
167
|
+
obj_ids : `np.ndarray`, opt
|
|
168
|
+
The object ids for which to generate ephemerides.
|
|
169
|
+
If None, then just uses all objects.
|
|
170
|
+
extrapolate : `bool`, opt
|
|
171
|
+
If True, extrapolate beyond ends of segments if time
|
|
172
|
+
outside of segment range.
|
|
173
|
+
If False, return ValueError if time is beyond range of segments.
|
|
174
|
+
|
|
175
|
+
Returns
|
|
176
|
+
-------
|
|
177
|
+
ephemerides : `np.ndarray`
|
|
178
|
+
The ephemeris positions for all objects.
|
|
179
|
+
Note that these may not be sorted in the same order as obj_ids.
|
|
180
|
+
"""
|
|
181
|
+
if isinstance(times, float) or isinstance(times, int):
|
|
182
|
+
times = np.array([times], float)
|
|
183
|
+
ntimes = len(times)
|
|
184
|
+
ephemerides = {}
|
|
185
|
+
# Find subset of segments which match obj_id, if specified.
|
|
186
|
+
if obj_ids is None:
|
|
187
|
+
obj_match = np.ones(len(self.coeffs["obj_id"]), dtype=bool)
|
|
188
|
+
ephemerides["obj_id"] = np.unique(self.coeffs["obj_id"])
|
|
189
|
+
else:
|
|
190
|
+
if isinstance(obj_ids, str) or isinstance(obj_ids, int):
|
|
191
|
+
obj_ids = np.array([obj_ids])
|
|
192
|
+
obj_match = np.isin(self.coeffs["obj_id"], obj_ids)
|
|
193
|
+
ephemerides["obj_id"] = obj_ids
|
|
194
|
+
# Now find ephemeris values.
|
|
195
|
+
ephemerides["time"] = np.zeros((len(ephemerides["obj_id"]), ntimes), float) + times
|
|
196
|
+
for k in self.ephemeris_keys:
|
|
197
|
+
ephemerides[k] = np.zeros((len(ephemerides["obj_id"]), ntimes), float)
|
|
198
|
+
for it, t in enumerate(times):
|
|
199
|
+
# Find subset of segments which contain the appropriate time.
|
|
200
|
+
# Look for simplest subset first.
|
|
201
|
+
segments = np.where(
|
|
202
|
+
(self.coeffs["t_start"][obj_match] <= t) & (self.coeffs["t_end"][obj_match] > t)
|
|
203
|
+
)[0]
|
|
204
|
+
if len(segments) == 0:
|
|
205
|
+
seg_start = self.coeffs["t_start"][obj_match].min()
|
|
206
|
+
seg_end = self.coeffs["t_end"][obj_match].max()
|
|
207
|
+
if seg_start > t or seg_end < t:
|
|
208
|
+
if not extrapolate:
|
|
209
|
+
for k in self.ephemeris_keys:
|
|
210
|
+
ephemerides[k][:, it] = np.nan
|
|
211
|
+
else:
|
|
212
|
+
# Find the segments to use to extrapolate the times.
|
|
213
|
+
if seg_start > t:
|
|
214
|
+
segments = np.where(self.coeffs["t_start"][obj_match] == seg_start)[0]
|
|
215
|
+
if seg_end < t:
|
|
216
|
+
segments = np.where(self.coeffs["t_end"][obj_match] == seg_end)[0]
|
|
217
|
+
elif seg_end == t:
|
|
218
|
+
# Not extrapolating, but outside the
|
|
219
|
+
# simple match case above.
|
|
220
|
+
segments = np.where(self.coeffs["t_end"][obj_match] == seg_end)[0]
|
|
221
|
+
for i, segmentIdx in enumerate(segments):
|
|
222
|
+
ephemeris = self._eval_segment(segmentIdx, t, obj_match, mask=False)
|
|
223
|
+
for k in self.ephemeris_keys:
|
|
224
|
+
ephemerides[k][i][it] = ephemeris[k]
|
|
225
|
+
ephemerides["obj_id"][i] = self.coeffs["obj_id"][obj_match][segmentIdx]
|
|
226
|
+
if obj_ids is not None:
|
|
227
|
+
if set(ephemerides["obj_id"]) != set(obj_ids):
|
|
228
|
+
raise ValueError(
|
|
229
|
+
"Did not find expected match between obj_ids provided and ephemeride obj_ids."
|
|
230
|
+
)
|
|
231
|
+
return ephemerides
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
"""Utilities to estimate and evaluate Chebyshev coefficients of a function.
|
|
2
|
+
|
|
3
|
+
Implementation of Newhall, X. X. 1989, Celestial Mechanics, 45, p. 305-310
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
__all__ = ("chebeval", "chebfit", "make_cheb_matrix", "make_cheb_matrix_only_x")
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
|
|
10
|
+
# Evaluation routine.
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def chebeval(x, p, interval=(-1.0, 1.0), do_velocity=True, mask=False):
|
|
14
|
+
"""Evaluate a Chebyshev series and first derivative at points x.
|
|
15
|
+
|
|
16
|
+
If p is of length n + 1, this function returns:
|
|
17
|
+
y_hat(x) = p_0 * T_0(x*) + p_1 * T_1(x*) + ... + p_n * T_n(x*)
|
|
18
|
+
where T_n(x*) are the orthogonal Chebyshev polynomials of the
|
|
19
|
+
first kind, defined on the interval [-1, 1] and p_n are the
|
|
20
|
+
coefficients. The scaled variable x* is defined on the [-1, 1]
|
|
21
|
+
interval such that (x*) = (2*x - a - b)/(b - a), and x is defined
|
|
22
|
+
on the [a, b] interval.
|
|
23
|
+
|
|
24
|
+
Parameters
|
|
25
|
+
----------
|
|
26
|
+
x : `scalar` or `np.ndarray`
|
|
27
|
+
Points at which to evaluate the polynomial.
|
|
28
|
+
p : `np.ndarray`
|
|
29
|
+
Chebyshev polynomial coefficients, as returned by chebfit.
|
|
30
|
+
interval : 2-element list/tuple
|
|
31
|
+
Bounds the x-interval on which the Chebyshev coefficients were fit.
|
|
32
|
+
do_velocity : `bool`
|
|
33
|
+
If True, compute the first derivative at points x.
|
|
34
|
+
mask : `bool`
|
|
35
|
+
If True, return Nans when the x goes beyond 'interval'.
|
|
36
|
+
If False, extrapolate fit beyond 'interval' limits.
|
|
37
|
+
|
|
38
|
+
Returns
|
|
39
|
+
-------
|
|
40
|
+
y, v : `float` or `np.ndarray`, `float` or `np.ndarray` (or None)
|
|
41
|
+
Y (position) and velocity values (if computed)
|
|
42
|
+
"""
|
|
43
|
+
if len(interval) != 2:
|
|
44
|
+
raise RuntimeError("interval must have length 2")
|
|
45
|
+
|
|
46
|
+
interval_begin = float(interval[0])
|
|
47
|
+
interval_end = float(interval[-1])
|
|
48
|
+
t = 2.0 * np.array(x, dtype=np.float64) - interval_begin - interval_end
|
|
49
|
+
t /= interval_end - interval_begin
|
|
50
|
+
|
|
51
|
+
y = 0.0
|
|
52
|
+
v = 0.0
|
|
53
|
+
y0 = np.ones_like(t)
|
|
54
|
+
y1 = t
|
|
55
|
+
v0 = np.zeros_like(t)
|
|
56
|
+
v1 = np.ones_like(t)
|
|
57
|
+
v2 = 4.0 * t
|
|
58
|
+
t = 2.0 * t
|
|
59
|
+
N = len(p)
|
|
60
|
+
|
|
61
|
+
if do_velocity:
|
|
62
|
+
for i in np.arange(0, N, 2):
|
|
63
|
+
if i == N - 1:
|
|
64
|
+
y1 = 0.0
|
|
65
|
+
v1 = 0.0
|
|
66
|
+
j = min(i + 1, N - 1)
|
|
67
|
+
|
|
68
|
+
y += p[i] * y0 + p[j] * y1
|
|
69
|
+
v += p[i] * v0 + p[j] * v1
|
|
70
|
+
|
|
71
|
+
y2 = t * y1 - y0
|
|
72
|
+
y3 = t * y2 - y1
|
|
73
|
+
v2 = t * v1 - v0 + 2 * y1
|
|
74
|
+
v3 = t * v2 - v1 + 2 * y2
|
|
75
|
+
|
|
76
|
+
y0 = y2
|
|
77
|
+
y1 = y3
|
|
78
|
+
v0 = v2
|
|
79
|
+
v1 = v3
|
|
80
|
+
|
|
81
|
+
if mask:
|
|
82
|
+
mask = np.where((x < interval_begin) | (x > interval_end), True, False)
|
|
83
|
+
y = np.where(mask, np.nan, y)
|
|
84
|
+
v = np.where(mask, np.nan, v)
|
|
85
|
+
return y, 2 * v / (interval_end - interval_begin)
|
|
86
|
+
else:
|
|
87
|
+
for i in np.arange(0, N, 2):
|
|
88
|
+
if i == N - 1:
|
|
89
|
+
y1 = 0.0
|
|
90
|
+
j = min((i + 1), (N - 1))
|
|
91
|
+
y += p[i] * y0 + p[j] * y1
|
|
92
|
+
y0 = t * y1 - y0
|
|
93
|
+
y1 = t * y0 - y1
|
|
94
|
+
if mask:
|
|
95
|
+
mask = np.where((x < interval_begin) | (x > interval_end), True, False)
|
|
96
|
+
y = np.where(mask, np.nan, y)
|
|
97
|
+
return y, None
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
# Fitting routines.
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def make_cheb_matrix(n_points, n_poly, weight=0.16):
|
|
104
|
+
"""Compute C1^(-1)C2 using Newhall89 approach.
|
|
105
|
+
|
|
106
|
+
Utility function for fitting chebyshev polynomials to
|
|
107
|
+
x(t) and dx/dt(t) forcing equality at the end points.
|
|
108
|
+
This function computes the matrix (C1^(-1)C2).
|
|
109
|
+
Multiplying this matrix by the x and dx/dt values to be fit
|
|
110
|
+
produces the chebyshev coefficient.
|
|
111
|
+
This function need only be called once for a given polynomial degree and
|
|
112
|
+
number of points.
|
|
113
|
+
|
|
114
|
+
The matrices returned are of shape(n_points+1)x(n_poly).
|
|
115
|
+
The coefficients fitting the n_points+1 points, X, are found by:
|
|
116
|
+
A = xMultiplier * x + dxMultiplier * dxdt
|
|
117
|
+
if derivative information is known, or
|
|
118
|
+
A = xMultiplier * x
|
|
119
|
+
if no derivative information is known.
|
|
120
|
+
The xMultiplier matrices are different,
|
|
121
|
+
depending on whether derivative information is known.
|
|
122
|
+
Use function make_cheb_matrix_only_x if derviative is not known.
|
|
123
|
+
See Newhall, X. X. 1989, Celestial Mechanics, 45, p. 305-310 for details.
|
|
124
|
+
|
|
125
|
+
Parameters
|
|
126
|
+
----------
|
|
127
|
+
n_points : `int`
|
|
128
|
+
Number of point to be fits. Must be greater than 2.
|
|
129
|
+
n_poly : `int`
|
|
130
|
+
Number of polynomial terms. Polynomial degree + 1
|
|
131
|
+
weight : `float`, optional
|
|
132
|
+
Weight to allow control of relative effectos of position and velocity
|
|
133
|
+
values. Newhall80 found best results are obtained with
|
|
134
|
+
velocity weighted at 0.4 relative to position,
|
|
135
|
+
giving W the form (1.0, 0.16, 1.0, 0.16,...)
|
|
136
|
+
|
|
137
|
+
Returns
|
|
138
|
+
-------
|
|
139
|
+
c1c2: `np.ndarray`
|
|
140
|
+
xMultiplier, C1^(-1)C2 even rows of shape (n_points+1)x(n_poly) to
|
|
141
|
+
be multiplied by x values.
|
|
142
|
+
c1c2: `np.ndarray`
|
|
143
|
+
dxMultiplier, C1^(-1)C2 odd rows of shape (n_points+1)x(n_poly) to
|
|
144
|
+
be multiplied by dx/dy values
|
|
145
|
+
"""
|
|
146
|
+
tmat = np.zeros([n_points, n_poly])
|
|
147
|
+
tdot = np.zeros([n_points, n_poly])
|
|
148
|
+
|
|
149
|
+
cj = np.zeros([n_poly])
|
|
150
|
+
xj = np.linspace(1, -1, n_points)
|
|
151
|
+
|
|
152
|
+
for i in np.arange(0, n_poly):
|
|
153
|
+
cj[:] = 0
|
|
154
|
+
cj[i] = 1
|
|
155
|
+
y, v = chebeval(xj, cj)
|
|
156
|
+
tmat[:, i] = y
|
|
157
|
+
tdot[:, i] = v
|
|
158
|
+
|
|
159
|
+
# make matrix T*W
|
|
160
|
+
tw = np.zeros([n_poly, n_points, 2])
|
|
161
|
+
tw[:, :, 0] = tmat.transpose()
|
|
162
|
+
tw[:, :, 1] = tdot.transpose() * weight
|
|
163
|
+
|
|
164
|
+
# make matrix T*WT
|
|
165
|
+
twt = np.dot(tw[:, :, 0], tmat) + np.dot(tw[:, :, 1], tdot)
|
|
166
|
+
tw = tw.reshape(n_poly, 2 * n_points)
|
|
167
|
+
|
|
168
|
+
# insert matrix T*W in matrix C2
|
|
169
|
+
c2 = np.zeros([n_poly + 4, 2 * n_points])
|
|
170
|
+
c2[0:n_poly] = tw
|
|
171
|
+
c2[n_poly, 0] = 1
|
|
172
|
+
c2[n_poly + 1, 1] = 1
|
|
173
|
+
c2[n_poly + 2, -2] = 1
|
|
174
|
+
c2[n_poly + 3, -1] = 1
|
|
175
|
+
|
|
176
|
+
# insert matrix T*WT in matrix C1
|
|
177
|
+
c1 = np.zeros([n_poly + 4, n_poly + 4])
|
|
178
|
+
c1[0:n_poly, 0:n_poly] = twt
|
|
179
|
+
c1[n_poly + 0, 0:n_poly] = tmat[0]
|
|
180
|
+
c1[n_poly + 1, 0:n_poly] = tdot[0]
|
|
181
|
+
c1[n_poly + 2, 0:n_poly] = tmat[-1]
|
|
182
|
+
c1[n_poly + 3, 0:n_poly] = tdot[-1]
|
|
183
|
+
|
|
184
|
+
c1[0:n_poly, n_poly:] = c1[n_poly:, 0:n_poly].transpose()
|
|
185
|
+
|
|
186
|
+
c1inv = np.linalg.inv(c1)
|
|
187
|
+
c1c2 = np.dot(c1inv, c2)
|
|
188
|
+
c1c2 = c1c2.reshape(n_poly + 4, n_points, 2)
|
|
189
|
+
c1c2 = c1c2[:, ::-1, :]
|
|
190
|
+
c1c2 = c1c2.reshape(n_poly + 4, 2 * n_points)
|
|
191
|
+
|
|
192
|
+
# separate even rows for x, and odd rows for dx/dt
|
|
193
|
+
return c1c2[0:n_poly, 0::2], c1c2[0:n_poly, 1::2]
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def make_cheb_matrix_only_x(n_points, n_poly):
|
|
197
|
+
"""Compute C1^(-1)C2 using Newhall89 approach without dx/dt
|
|
198
|
+
|
|
199
|
+
Compute xMultiplier using only the equality constraint of the x-values
|
|
200
|
+
at the endpoints.
|
|
201
|
+
To be used when first derivatives are not available.
|
|
202
|
+
If chebyshev approximations are strung together piecewise only the x-values
|
|
203
|
+
and not the first derivatives will be continuous at the boundaries.
|
|
204
|
+
Multiplying this matrix by the x-values to be fit produces the chebyshev
|
|
205
|
+
coefficients. This function need only be called once for a given
|
|
206
|
+
polynomial degree and
|
|
207
|
+
number of points.
|
|
208
|
+
See Newhall, X. X. 1989, Celestial Mechanics, 45, p. 305-310.
|
|
209
|
+
|
|
210
|
+
Parameters
|
|
211
|
+
----------
|
|
212
|
+
n_points : `int`
|
|
213
|
+
Number of point to be fits. Must be greater than 2.
|
|
214
|
+
n_poly : `int`
|
|
215
|
+
Number of polynomial terms. Polynomial degree + 1
|
|
216
|
+
|
|
217
|
+
Returns
|
|
218
|
+
-------
|
|
219
|
+
c1c2: `np.ndarray`
|
|
220
|
+
xMultiplier, Even rows of C1^(-1)C2 w/ shape (n_points+1)x(n_poly)
|
|
221
|
+
to be multiplied by x values
|
|
222
|
+
"""
|
|
223
|
+
|
|
224
|
+
tmat = np.zeros([n_points, n_poly])
|
|
225
|
+
cj = np.zeros([n_poly])
|
|
226
|
+
xj = np.linspace(1, -1, n_points)
|
|
227
|
+
for i in range(0, n_poly):
|
|
228
|
+
cj[:] = 0
|
|
229
|
+
cj[i] = 1
|
|
230
|
+
tmat[:, i], v = chebeval(xj, cj)
|
|
231
|
+
|
|
232
|
+
# Augment matrix T to get matrix C2
|
|
233
|
+
c2 = np.zeros([n_poly + 2, n_points])
|
|
234
|
+
c2[0:n_poly] = tmat.transpose()
|
|
235
|
+
c2[n_poly, 0] = 1
|
|
236
|
+
c2[n_poly + 1, n_points - 1] = 1
|
|
237
|
+
|
|
238
|
+
# Augment matrix T*WT to get the matrix C1
|
|
239
|
+
c1 = np.zeros([n_poly + 2, n_poly + 2])
|
|
240
|
+
c1[0:n_poly, 0:n_poly] = np.dot(tmat.transpose(), tmat)
|
|
241
|
+
c1[n_poly + 0, 0:n_poly] = tmat[0]
|
|
242
|
+
c1[n_poly + 1, 0:n_poly] = tmat[-1]
|
|
243
|
+
c1[0:n_poly, n_poly:] = c1[n_poly:, 0:n_poly].transpose()
|
|
244
|
+
|
|
245
|
+
c1inv = np.linalg.inv(c1)
|
|
246
|
+
# C1^(-1) C2
|
|
247
|
+
c1c2 = np.dot(c1inv, c2)
|
|
248
|
+
|
|
249
|
+
c1c2 = c1c2.reshape(n_poly + 2, n_points)
|
|
250
|
+
c1c2 = c1c2[:, ::-1]
|
|
251
|
+
return c1c2[0:n_poly]
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def chebfit(t, x, dxdt=None, x_multiplier=None, dx_multiplier=None, n_poly=7):
|
|
255
|
+
"""Fit Chebyshev polynomial constrained at endpoints using
|
|
256
|
+
Newhall89 approach.
|
|
257
|
+
|
|
258
|
+
Return Chebyshev coefficients and statistics from fit
|
|
259
|
+
to array of positions (x) and optional velocities (dx/dt).
|
|
260
|
+
If both the function and its derivative are specified, then the value and
|
|
261
|
+
derivative of the interpolating polynomial at the
|
|
262
|
+
endpoints will be exactly equal to the input endpoint values.
|
|
263
|
+
Many approximations may be piecewise strung together and the function value
|
|
264
|
+
and its first derivative will be continuous across boundaries.
|
|
265
|
+
If derivatives are not provided, only the function value will be
|
|
266
|
+
continuous across boundaries.
|
|
267
|
+
|
|
268
|
+
If x_multiplier and dx_multiplier are not provided or
|
|
269
|
+
are an inappropriate shape for t and x, they will be recomputed.
|
|
270
|
+
See Newhall, X. X. 1989, Celestial Mechanics, 45, p. 305-310
|
|
271
|
+
for details.
|
|
272
|
+
|
|
273
|
+
Parameters
|
|
274
|
+
----------
|
|
275
|
+
t : `np.ndarray`
|
|
276
|
+
Array of regularly sampled independent variable (e.g. time)
|
|
277
|
+
x : `np.ndarray`
|
|
278
|
+
Array of regularly sampled dependent variable (e.g. declination)
|
|
279
|
+
dxdt : `np.ndarray', optional
|
|
280
|
+
Optionally, array of first derivatives of x with respect to t,
|
|
281
|
+
at the same grid points. (e.g. sky velocity ddecl/dt)
|
|
282
|
+
x_multiplier : `np.ndarray`, optional
|
|
283
|
+
Optional 2D Matrix with rows of C1^(-1)C2 corresponding to x.
|
|
284
|
+
Use make_cheb_matrix to compute
|
|
285
|
+
dx_multiplier : `np.ndarray`, optional
|
|
286
|
+
Optional 2D Matrix with rows of C1^(-1)C2 corresponding to dx/dt.
|
|
287
|
+
Use make_cheb_matrix to compute
|
|
288
|
+
n_poly : `int`, optional
|
|
289
|
+
Number of polynomial terms. Degree + 1. Must be >=2 and <=2*n_points,
|
|
290
|
+
when derivative information is specified, or <=n_points, when no
|
|
291
|
+
derivative information is specified. Default = 7.
|
|
292
|
+
|
|
293
|
+
Returns
|
|
294
|
+
-------
|
|
295
|
+
a_n : `np.ndarray`
|
|
296
|
+
Array of chebyshev coefficients with length=n_poly.
|
|
297
|
+
residuals : `np.ndarray`
|
|
298
|
+
Array of residuals of the tabulated function x minus the
|
|
299
|
+
approximated function.
|
|
300
|
+
rms : `float`
|
|
301
|
+
The rms of the residuals in the fit.
|
|
302
|
+
maxresid : `float`
|
|
303
|
+
The maximum of the residals to the fit.
|
|
304
|
+
"""
|
|
305
|
+
n_points = len(t)
|
|
306
|
+
if len(x) != n_points:
|
|
307
|
+
raise ValueError("length of x (%s) != length of t (%s)" % (len(x), n_points))
|
|
308
|
+
if dxdt is None:
|
|
309
|
+
if n_poly > n_points:
|
|
310
|
+
raise RuntimeError(
|
|
311
|
+
"Without velocity constraints, n_poly (%d) must be less than %s" % (n_poly, n_points)
|
|
312
|
+
)
|
|
313
|
+
if n_poly < 2:
|
|
314
|
+
raise RuntimeError("Without velocity constraints, n_poly (%d) must be greater than 2" % n_poly)
|
|
315
|
+
else:
|
|
316
|
+
if n_poly > 2 * n_points:
|
|
317
|
+
raise RuntimeError(
|
|
318
|
+
"n_poly (%d) must be less than %s (%d)" % (n_poly, "2 * n_points", 2 * (n_points))
|
|
319
|
+
)
|
|
320
|
+
if n_poly < 4:
|
|
321
|
+
raise RuntimeError("n_poly (%d) must be greater than 4" % n_poly)
|
|
322
|
+
|
|
323
|
+
# Recompute C1invX2 if x_multiplier and dx_multiplier are None or
|
|
324
|
+
# they are not appropriate for sizes of input positions and velocities.
|
|
325
|
+
|
|
326
|
+
if x_multiplier is None:
|
|
327
|
+
redo_x = True
|
|
328
|
+
else:
|
|
329
|
+
redo_x = (x_multiplier.shape[1] != n_points) | (x_multiplier.shape[0] != n_poly)
|
|
330
|
+
|
|
331
|
+
if dx_multiplier is None:
|
|
332
|
+
redo_v = True
|
|
333
|
+
else:
|
|
334
|
+
redo_v = (dx_multiplier.shape[1] != n_points) | (dx_multiplier.shape[0] != n_poly)
|
|
335
|
+
|
|
336
|
+
if (dxdt is None) & redo_x:
|
|
337
|
+
x_multiplier = make_cheb_matrix_only_x(n_points, n_poly)
|
|
338
|
+
|
|
339
|
+
if (dxdt is not None) & (redo_v | redo_x):
|
|
340
|
+
x_multiplier, dx_multiplier = make_cheb_matrix(n_points, n_poly)
|
|
341
|
+
|
|
342
|
+
if x.size != n_points:
|
|
343
|
+
raise RuntimeError("Not enough elements in X")
|
|
344
|
+
|
|
345
|
+
t_interval = np.array([t[0], t[-1]]) - t[0]
|
|
346
|
+
t_scaled = t - t[0]
|
|
347
|
+
|
|
348
|
+
# Compute the X portion of the coefficients
|
|
349
|
+
a_n = np.dot(x_multiplier, x)
|
|
350
|
+
|
|
351
|
+
# Compute statistics
|
|
352
|
+
# for x and dxdt if it is available
|
|
353
|
+
if dxdt is not None:
|
|
354
|
+
a_n = a_n + np.dot(dx_multiplier, dxdt * (t_interval[1] - t_interval[0]) / 2.0)
|
|
355
|
+
x_approx, dx_approx = chebeval(t_scaled, a_n, interval=t_interval)
|
|
356
|
+
else:
|
|
357
|
+
# Statistics for x only
|
|
358
|
+
x_approx, _ = chebeval(t_scaled, a_n, interval=t_interval, do_velocity=False)
|
|
359
|
+
|
|
360
|
+
residuals = x - x_approx
|
|
361
|
+
se = np.sum(residuals**2)
|
|
362
|
+
rms = np.sqrt(se / (n_points - 1))
|
|
363
|
+
maxresid = np.max(np.abs(residuals))
|
|
364
|
+
|
|
365
|
+
return a_n, residuals, rms, maxresid
|