spectro-kernel 0.3.0__tar.gz → 0.4.0__tar.gz
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.
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/CHANGELOG.md +118 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/PKG-INFO +1 -1
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/gen_catalogue.py +3 -0
- spectro_kernel-0.4.0/src/spectro_kernel/algorithms/advanced/doppler_tomogram.py +311 -0
- spectro_kernel-0.4.0/src/spectro_kernel/algorithms/classification/classify_template_chi2.py +292 -0
- spectro_kernel-0.4.0/src/spectro_kernel/algorithms/classification/pickles_atlas.py +151 -0
- spectro_kernel-0.4.0/src/spectro_kernel/algorithms/kinematics/rotation_curve.py +241 -0
- spectro_kernel-0.4.0/src/spectro_kernel/algorithms/lines/_line_flux.py +152 -0
- spectro_kernel-0.4.0/src/spectro_kernel/algorithms/lines/detect.py +348 -0
- spectro_kernel-0.4.0/src/spectro_kernel/algorithms/lines/vr_ratio.py +287 -0
- spectro_kernel-0.4.0/src/spectro_kernel/algorithms/nebular/__init__.py +0 -0
- spectro_kernel-0.4.0/src/spectro_kernel/algorithms/nebular/bpt_line_ratios.py +242 -0
- spectro_kernel-0.4.0/src/spectro_kernel/algorithms/nebular/oiii_electron_temperature.py +218 -0
- spectro_kernel-0.4.0/src/spectro_kernel/algorithms/nebular/sii_electron_density.py +222 -0
- spectro_kernel-0.4.0/src/spectro_kernel/algorithms/rv/redshift_lines.py +239 -0
- spectro_kernel-0.4.0/src/spectro_kernel/py.typed +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/types/enums.py +5 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/version.py +1 -1
- spectro_kernel-0.4.0/src/spectro_mcp/py.typed +0 -0
- spectro_kernel-0.4.0/tests/unit/test_classify_template_chi2.py +108 -0
- spectro_kernel-0.4.0/tests/unit/test_detect_lines_blind.py +119 -0
- spectro_kernel-0.4.0/tests/unit/test_doppler_tomogram.py +79 -0
- spectro_kernel-0.4.0/tests/unit/test_nebular_diagnostics.py +167 -0
- spectro_kernel-0.4.0/tests/unit/test_redshift_lines.py +50 -0
- spectro_kernel-0.4.0/tests/unit/test_rotation_curve.py +68 -0
- spectro_kernel-0.4.0/tests/unit/test_vr_ratio.py +60 -0
- spectro_kernel-0.3.0/src/spectro_kernel/algorithms/lines/detect.py +0 -157
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/.gitignore +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/LICENSE +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/README.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/concepts/algorithms.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/concepts/architecture.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/concepts/data-types.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/concepts/pipelines.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/contributing.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/cookbook/bess-dashboard.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/cookbook/multi-star-viewer.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/cookbook/web-playground.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/getting-started.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/images/notebooks/alpha_cyg_ew_timeseries.png +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/images/notebooks/alpha_cyg_halpha_phase_stack.png +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/images/notebooks/alpha_cyg_halpha_timeseries.png +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/images/notebooks/alpha_cyg_overlay.png +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/images/notebooks/alpha_cyg_pc1_vs_phase.png +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/images/notebooks/alpha_cyg_pca_2d.png +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/images/notebooks/alpha_cyg_pca_3d.png +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/images/notebooks/alpha_cyg_periodogram.png +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/images/notebooks/alpha_cyg_phase_folded.png +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/images/notebooks/alpha_cyg_rv_timeseries.png +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/images/notebooks/alpha_cyg_similarity.png +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/images/notebooks/alpha_cyg_similarity_date.png +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/images/notebooks/alpha_dra_halpha_phase_stack.png +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/images/notebooks/alpha_dra_pc1_vs_phase.png +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/images/notebooks/alpha_dra_pca_2d.png +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/images/notebooks/alpha_dra_pca_3d.png +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/images/notebooks/alpha_dra_periodogram.png +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/images/notebooks/alpha_dra_phase_folded.png +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/images/notebooks/alpha_dra_rv_timeseries.png +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/images/notebooks/alpha_dra_similarity_date.png +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/images/notebooks/alpha_dra_similarity_phase.png +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/index.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/notebooks/alpha-cyg-time-series.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/notebooks/alpha-dra-binary-period.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/notebooks/aurora-line-monitor.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/notebooks/be-star-variability.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/notebooks/claude-mcp-end-to-end.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/notebooks/exoplanet-transit-rv.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/notebooks/full-reduction-walkthrough.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/notebooks/native-vs-easyspec-showdown.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/notebooks/your-first-sb2.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/reference.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/tutorials/add-an-algorithm.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/tutorials/analyse-a-spectrum.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/tutorials/discover-the-catalogue.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/tutorials/first-spectrum.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/tutorials/long-slit-reduction.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/usage/cli.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/usage/library.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/usage/mcp.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/docs/why.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/playground/README.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/pyproject.toml +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/__init__.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/adapters/__init__.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/adapters/easyspec.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/__init__.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/_common.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/advanced/__init__.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/advanced/aperture_photometry.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/advanced/disentangle_sb2.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/catalogs/__init__.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/catalogs/gaia.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/catalogs/simbad.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/catalogs/vizier.py +0 -0
- {spectro_kernel-0.3.0/src/spectro_kernel/algorithms/embedding → spectro_kernel-0.4.0/src/spectro_kernel/algorithms/classification}/__init__.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/continuum/__init__.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/continuum/compare_normalisations.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/continuum/normalize_edges.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/continuum/normalize_max.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/continuum/normalize_percentile.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/continuum/normalize_polynomial.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/continuum/normalize_region.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/continuum/subtract_continuum.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/corrections/__init__.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/corrections/air_vacuum.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/corrections/barycentric.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/corrections/doppler_shift.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/corrections/extinction_correct_easyspec.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/corrections/fit_telluric_scaling.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/corrections/flux_calibrate_easyspec.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/corrections/remove_telluric.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/corrections/response_from_standard.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/corrections/synth_telluric.py +0 -0
- /spectro_kernel-0.3.0/src/spectro_kernel/py.typed → /spectro_kernel-0.4.0/src/spectro_kernel/algorithms/embedding/__init__.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/embedding/embed_band_power.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/embedding/embed_continuum_subtracted.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/embedding/embed_lick_indices.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/embedding/embed_log_lambda.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/embedding/embed_pretrained.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/embedding/embed_remote.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/embedding/embed_spectrum.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/embedding/embed_wavelets.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/exports/__init__.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/exports/export_csv.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/exports/export_fits.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/exports/export_fits_bess.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/exports/export_hdf5.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/exports/export_votable.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/extraction/__init__.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/extraction/boxcar.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/extraction/detect_trace.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/extraction/easyspec_extract.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/extraction/optimal.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/extraction/sky_lateral_bands.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/io/__init__.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/io/read_ascii.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/io/read_echelle.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/io/read_fits.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/io/read_sdss.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/io/read_votable.py +0 -0
- /spectro_kernel-0.3.0/src/spectro_mcp/py.typed → /spectro_kernel-0.4.0/src/spectro_kernel/algorithms/kinematics/__init__.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/lines/__init__.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/lines/_profiles.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/lines/catalogs.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/lines/compare_line_fits.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/lines/equivalent_width.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/lines/fit_gaussian.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/lines/fit_lorentzian.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/lines/fit_voigt.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/quality/__init__.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/quality/compare_snr_methods.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/quality/snr_der.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/quality/snr_edge.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/quality/snr_linear_fit.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/reduction/__init__.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/reduction/_easyspec_apply.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/reduction/_easyspec_helpers.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/reduction/bias_combine.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/reduction/clip_cosmic_rays.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/reduction/dark_combine.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/reduction/dark_subtract.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/reduction/denoise_2d.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/reduction/easyspec_bias.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/reduction/easyspec_cosmic_ray.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/reduction/easyspec_dark.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/reduction/easyspec_flat.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/reduction/easyspec_flat_normalize.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/reduction/easyspec_subtract_bias.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/reduction/easyspec_subtract_dark.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/reduction/extract_spectrum_sum.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/reduction/flat_combine.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/reduction/flat_normalize.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/reduction/geometry.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/reduction/subtract_sky_2d.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/reduction/wavelength_calibrate.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/rv/__init__.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/rv/cross_correlate.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/rv/fit_keplerian_orbit.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/rv/measure.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/rv/precision_bouchy.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/smoothing/__init__.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/smoothing/compare_smoothings.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/smoothing/smooth_gaussian.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/smoothing/smooth_savgol.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/stacking/__init__.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/stacking/merge_echelle_orders.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/stacking/stack.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/timeseries/__init__.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/timeseries/lomb_scargle.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/timeseries/phase_fold.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/transforms/__init__.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/transforms/clip_sigma.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/transforms/combine_arithmetic.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/transforms/extract_region.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/transforms/mask_range.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/transforms/resample.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/transforms/resample_flux_conserving.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/viz/__init__.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/viz/plot_3d_surface.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/viz/plot_animation.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/viz/plot_dynamic_spectrum.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/viz/plot_plotly.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/wavelength_calibration/__init__.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/wavelength_calibration/arc_geometry.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/wavelength_calibration/easyspec_wavelength.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/wavelength_calibration/in_situ.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/wavelength_calibration/lamp_atlas.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/wavelength_calibration/match_lamp.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/algorithms/wavelength_calibration/solar.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/base.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/cli.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/embeddings.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/errors.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/io/__init__.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/io/ascii.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/io/fits.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/io/votable.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/pipeline.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/presets/__init__.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/presets/catalog/analysis/balmer_quick.yaml +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/presets/catalog/analysis/embed_quick.yaml +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/presets/catalog/analysis/quality_report.yaml +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/presets/catalog/analysis/rv_quick.yaml +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/presets/catalog/analysis/snr_check.yaml +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/presets/catalog/analysis/time_series_overview.yaml +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/presets/catalog/reduction/full_reduction_easyspec.yaml +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/presets/loader.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/registry.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/types/__init__.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/types/catalog.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/types/context.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/types/history.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/types/image.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/types/line.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/types/spectrum.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_kernel/types/timeseries.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_mcp/__init__.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_mcp/__main__.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_mcp/auth.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_mcp/auto_tools.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_mcp/observability.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_mcp/server.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_mcp/session.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/src/spectro_mcp/url_safety.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/conftest.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/reference/conftest.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/reference/data/.gitkeep +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/reference/data/README.md +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/reference/data/sun/sun_reference_stis_002.fits +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/reference/data/vega/alpha_lyr_stis_011.fits +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/reference/test_known_answers.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/reference/test_sun.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/reference/test_vega.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_base.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_cli.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_combine.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_combine_arithmetic.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_continuum.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_corrections.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_dark_flat_combine.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_denoise_2d.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_detect_trace.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_easyspec_apply_staging.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_easyspec_wrappers.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_embedding.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_embedding_pretrained.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_embedding_remote_lick.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_embedding_tier1.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_export_fits_bess.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_extract_boxcar.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_extract_optimal.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_geometry_corrections.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_io.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_lamp_atlas_match.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_line_profiles.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_lines.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_mcp.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_mcp_production.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_mcp_security.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_measure_arc_geometry.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_misc_algorithms.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_no_circular_imports.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_normalize_to_region.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_pipeline.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_quality.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_read_sdss.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_registry.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_response_from_standard.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_sky_lateral_bands.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_smoothing.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_timeseries.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_transforms.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_types.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_viz.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_wavelength_calibration_in_situ.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/tests/unit/test_wavelength_calibration_solar.py +0 -0
- {spectro_kernel-0.3.0 → spectro_kernel-0.4.0}/website/README.md +0 -0
|
@@ -6,6 +6,124 @@ Until `1.0.0` the public API may change between minor versions.
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.4.0] — 2026-06-26
|
|
10
|
+
|
|
11
|
+
A scientific catalogue expansion driven by a downstream
|
|
12
|
+
dashboard's needs (STAROS, see `stuff/spectro_kernel_spec_25_06_26.md`).
|
|
13
|
+
Adds **8 new algorithms across 3 new categories** (`nebular`,
|
|
14
|
+
`kinematics`, `classification`), extends `detect_lines` with a
|
|
15
|
+
blind mode (no catalogue identification), and factors a shared
|
|
16
|
+
Gaussian-line-flux primitive used by the nebular diagnostics.
|
|
17
|
+
|
|
18
|
+
Each new brick cites the literature paper that defines its formula
|
|
19
|
+
(no fabricated references) and reproduces the published coefficients
|
|
20
|
+
verbatim in code.
|
|
21
|
+
|
|
22
|
+
### Added — nebular diagnostics (3 algorithms)
|
|
23
|
+
|
|
24
|
+
- **`oiii_electron_temperature`** (category `nebular`) — electron
|
|
25
|
+
temperature Te from the [O III] λ4363/λ5007 auroral-to-nebular
|
|
26
|
+
ratio. Implements the 5-level inversion of **Aller 1984**
|
|
27
|
+
(*Physics of Thermal Gaseous Nebulae*), as derived in
|
|
28
|
+
**Osterbrock & Ferland 2006** §5.6 :
|
|
29
|
+
``Te = 32900 / ln(R / 7.90)``. Valid for ``n_e ≲ 10⁵ cm⁻³`` and
|
|
30
|
+
``Te ∈ [3000, 30000] K`` ; outside that range the algorithm reports
|
|
31
|
+
``te_kelvin = NaN`` and tags the regime in ``extras["regime"]``.
|
|
32
|
+
- **`sii_electron_density`** (category `nebular`) — electron density
|
|
33
|
+
n_e from the [S II] λ6716/λ6731 ratio. Uses the polynomial-plus-arctan
|
|
34
|
+
fit of **Proxauf, Öttl & Kimeswenger 2014** (A&A 561, A10, Eq. 6,
|
|
35
|
+
coefficients copied verbatim) at Te ≈ 10⁴ K for
|
|
36
|
+
``0.45 ≲ R ≲ 1.43`` ; saturates cleanly at the low- and
|
|
37
|
+
high-density limits with explicit regime labelling.
|
|
38
|
+
- **`bpt_line_ratios`** (category `nebular`) — measures the 4
|
|
39
|
+
standard BPT log-ratios and classifies a galaxy as
|
|
40
|
+
``HII / Composite / Seyfert / LINER`` in the [N II]/Hα plane.
|
|
41
|
+
Demarcations from **Kauffmann et al. 2003** (MNRAS 346, 1055),
|
|
42
|
+
**Kewley & Dopita 2001** (ApJ 556, 121) and **Cid Fernandes
|
|
43
|
+
et al. 2010** (MNRAS 403, 1036) ; origin paper **Baldwin, Phillips
|
|
44
|
+
& Terlevich 1981** (PASP 93, 5).
|
|
45
|
+
|
|
46
|
+
### Added — binary / variable diagnostics (2 algorithms)
|
|
47
|
+
|
|
48
|
+
- **`vr_ratio`** (category `line_fitting`) — Violet/Red intensity
|
|
49
|
+
ratio of a double-peaked emission line, the standard asymmetry
|
|
50
|
+
diagnostic for Be-star circumstellar discs (Hα by default) and
|
|
51
|
+
any other source with a resolved double profile (symbiotic stars,
|
|
52
|
+
novae, AGN BLR). Theory grounding : **Okazaki 1991** (A&A 246,
|
|
53
|
+
415, one-armed density waves), **Hummel & Vrancken 2000** (A&A
|
|
54
|
+
359, 1075). Detection via ``scipy.signal.find_peaks`` on the
|
|
55
|
+
edge-continuum-normalised window.
|
|
56
|
+
- **`doppler_tomogram`** (category `advanced`) — Doppler tomography
|
|
57
|
+
of a binary system by **Marsh & Horne 1988** (MNRAS 235, 269) §2
|
|
58
|
+
back-projection. Reconstructs the brightness distribution
|
|
59
|
+
``I(V_x, V_y)`` from N phase-resolved spectra of a known-period
|
|
60
|
+
binary. NaN-aware averaging of the per-phase contributions keeps
|
|
61
|
+
the phase-coverage footprint out of the brightness map.
|
|
62
|
+
Complements the existing ``disentangle_sb2`` ; MEM (Horne 1985)
|
|
63
|
+
is left to a future v2.
|
|
64
|
+
|
|
65
|
+
### Added — extragalactic kinematics (2 algorithms)
|
|
66
|
+
|
|
67
|
+
- **`redshift_lines`** (category `radial_velocity`) — redshift z by
|
|
68
|
+
per-line Gaussian fits against a list of anchor lines (SDSS
|
|
69
|
+
spec1d style, **Stoughton et al. 2002** AJ 123, 485) ; default
|
|
70
|
+
list = 9 strong galaxy lines ([O II], Ca II H+K, Hβ, [O III],
|
|
71
|
+
Mg b, Na D, Hα, [N II]). Tries emission + absorption fits and
|
|
72
|
+
keeps the lower residual, so the same brick covers
|
|
73
|
+
emission-line galaxies and quiescent absorption-line systems.
|
|
74
|
+
- **`rotation_curve`** (category **kinematics**, new) — projected
|
|
75
|
+
long-slit rotation curve ``v_los(r)`` from per-spectrum Hα fits
|
|
76
|
+
indexed by slit offset (arcsec from galactic centre). Origin :
|
|
77
|
+
**Rubin et al. 1980** (ApJ 238, 471), reviewed in **Sofue &
|
|
78
|
+
Rubin 2001** (ARA&A 39, 137). Simple projection only — no
|
|
79
|
+
inclination correction, no asymmetric drift, no 2-D modelling.
|
|
80
|
+
|
|
81
|
+
### Added — spectral classification (1 algorithm + atlas loader)
|
|
82
|
+
|
|
83
|
+
- **`classify_template_chi2`** (category **classification**, new) —
|
|
84
|
+
spectral type by unweighted χ² against a Pickles-style template
|
|
85
|
+
atlas (**Pickles 1998**, PASP 110, 863). Returns top-N matches
|
|
86
|
+
plus confidence flags (``ambiguous`` = χ²[1]/χ²[0] < 1.20 ;
|
|
87
|
+
``teff_unstable`` = top-3 ``ΔT_eff`` > 500 K). The atlas itself
|
|
88
|
+
is **not bundled** (≈ 1 MB of data, redistribution OK with
|
|
89
|
+
attribution but kept out of the thin core install) ; a loader
|
|
90
|
+
helper :mod:`spectro_kernel.algorithms.classification.pickles_atlas`
|
|
91
|
+
reads the downloadable ASCII templates from ESO
|
|
92
|
+
(``ftp.eso.org/pub/stecf/standards/hststan/uvklib/``) or VizieR
|
|
93
|
+
(``J/PASP/110/863/``) into the algorithm's expected
|
|
94
|
+
:class:`Atlas` shape.
|
|
95
|
+
|
|
96
|
+
### Added — blind line detection (extension)
|
|
97
|
+
|
|
98
|
+
- **`detect_lines`** v1.1.0 → **v1.2.0**: a new ``catalog=None``
|
|
99
|
+
mode runs a blind detection (no catalogue identification) and
|
|
100
|
+
emits a richer schema per line (continuum, signed amplitude, SNR,
|
|
101
|
+
FWHM, prominence) plus the MAD-robust noise level
|
|
102
|
+
(``1.4826 · MAD``, Hampel 1974) used for the prominence
|
|
103
|
+
threshold. The v1.1.0 catalogue mode is preserved bit-exact.
|
|
104
|
+
|
|
105
|
+
### Added — shared primitive
|
|
106
|
+
|
|
107
|
+
- **`spectro_kernel.algorithms.lines._line_flux.gaussian_line_flux`** —
|
|
108
|
+
factored "Gaussian + local continuum" fit used by the three
|
|
109
|
+
nebular bricks. Window-edge continuum (median of the two outer
|
|
110
|
+
bands), ``curve_fit`` with seeds, analytic flux
|
|
111
|
+
``F = |amp| · |σ| · √(2π)``. Returns ``None`` on bad fits so
|
|
112
|
+
callers can degrade gracefully.
|
|
113
|
+
|
|
114
|
+
### Added — new categories
|
|
115
|
+
|
|
116
|
+
`AlgorithmCategory` gains `NEBULAR`, `KINEMATICS` and
|
|
117
|
+
`CLASSIFICATION` for the new specialised domains.
|
|
118
|
+
``docs/gen_catalogue.py`` gets matching titles so the catalogue
|
|
119
|
+
page renders them as *Nebular diagnostics*, *Kinematics* and
|
|
120
|
+
*Spectral classification*.
|
|
121
|
+
|
|
122
|
+
### Numbers
|
|
123
|
+
|
|
124
|
+
**113 algorithms** registered (was 105). 325 tests pass (32 new),
|
|
125
|
+
ruff clean, mkdocs strict OK.
|
|
126
|
+
|
|
9
127
|
## [0.3.0] — 2026-06-09
|
|
10
128
|
|
|
11
129
|
A focused expansion driven by the LineMill stellar-spectroscopy work
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: spectro-kernel
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: A shared catalogue of astronomical spectroscopy algorithms, composable into reproducible pipelines, usable as a Python library, a CLI, or an MCP server.
|
|
5
5
|
Project-URL: Homepage, https://github.com/matthieulel/spectro-kernel
|
|
6
6
|
Project-URL: Documentation, https://matthieulel.github.io/spectro-kernel/
|
|
@@ -30,6 +30,9 @@ _CATEGORY_TITLES = {
|
|
|
30
30
|
"timeseries": "Time series",
|
|
31
31
|
"stacking": "Stacking",
|
|
32
32
|
"embedding": "Embeddings",
|
|
33
|
+
"nebular": "Nebular diagnostics",
|
|
34
|
+
"kinematics": "Kinematics",
|
|
35
|
+
"classification": "Spectral classification",
|
|
33
36
|
"catalog": "External catalogues",
|
|
34
37
|
"visualization": "Visualisation",
|
|
35
38
|
"export": "Export",
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
"""Algorithm: Doppler tomography by back-projection (Marsh & Horne 1988).
|
|
2
|
+
|
|
3
|
+
Given N phase-resolved spectra of a known-period binary system, this
|
|
4
|
+
brick reconstructs the **brightness distribution in the velocity space
|
|
5
|
+
of the binary** ``I(V_x, V_y)`` by simple **back-projection** — the
|
|
6
|
+
direct inversion of the trailed-spectrogram → velocity-map mapping
|
|
7
|
+
established by Marsh & Horne 1988.
|
|
8
|
+
|
|
9
|
+
Mathematical model (§2 of Marsh & Horne 1988) :
|
|
10
|
+
|
|
11
|
+
For each spectrum taken at orbital phase ``φ ∈ [0, 1)``, the line
|
|
12
|
+
profile records the integral of ``I(V_x, V_y)`` along all lines of
|
|
13
|
+
sight projected onto the radial velocity
|
|
14
|
+
|
|
15
|
+
v(φ; V_x, V_y) = γ − V_x · sin(2π φ) + V_y · cos(2π φ) (Eq. 1)
|
|
16
|
+
|
|
17
|
+
where ``γ`` is the binary's systemic velocity. The back-projection
|
|
18
|
+
estimator inverts Eq. 1 by smearing each phase-spectrum along its own
|
|
19
|
+
sinusoidal locus in the ``(V_x, V_y)`` plane :
|
|
20
|
+
|
|
21
|
+
M(V_x, V_y) ≈ ⟨ I_φ(γ − V_x · sin 2πφ + V_y · cos 2πφ) ⟩_φ (Eq. 2)
|
|
22
|
+
|
|
23
|
+
where ``⟨·⟩_φ`` averages over phases that *contribute* to each
|
|
24
|
+
``(V_x, V_y)`` pixel (NaN-aware mean — pixels with no contributing
|
|
25
|
+
phase are reported as ``0``, not ``NaN/0``).
|
|
26
|
+
|
|
27
|
+
Back-projection is the simplest tomographic reconstruction; **Maximum
|
|
28
|
+
Entropy Method (MEM)** (Horne 1985) is a more advanced alternative
|
|
29
|
+
that suppresses the streak artefacts of pure back-projection. MEM is
|
|
30
|
+
intentionally left out of v1.0.0 to keep the surface tight.
|
|
31
|
+
|
|
32
|
+
Phase computation : ``φ = ((JD_mid − epoch_HJD) / period) mod 1``.
|
|
33
|
+
Each input ``Spectrum1D`` must carry its **mid-exposure JD** in
|
|
34
|
+
``spec.meta["jd_mid"]`` ; if absent, the algorithm falls back to
|
|
35
|
+
deriving it from ``spec.meta["dateobs"]`` and ``spec.meta["exptime_s"]``
|
|
36
|
+
(``jd_mid = Time(dateobs).jd + exptime_s / 2 / 86400``), which requires
|
|
37
|
+
``astropy.time`` (imported lazily).
|
|
38
|
+
|
|
39
|
+
References
|
|
40
|
+
----------
|
|
41
|
+
- **Marsh & Horne 1988**, MNRAS 235, 269 — *Images of accretion discs.
|
|
42
|
+
II. Doppler tomography* (the canonical back-projection paper).
|
|
43
|
+
- **Horne 1985**, MNRAS 213, 129 — MEM tomographic reconstruction
|
|
44
|
+
(not implemented; cited for completeness).
|
|
45
|
+
- **Marsh 2001**, *Astrotomography*, Lecture Notes in Physics 573 —
|
|
46
|
+
modern review (back-projection vs MEM vs χ² + regularised MEM).
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
from __future__ import annotations
|
|
50
|
+
|
|
51
|
+
import math
|
|
52
|
+
from typing import Any
|
|
53
|
+
|
|
54
|
+
import numpy as np
|
|
55
|
+
|
|
56
|
+
from ...base import AlgorithmOutput, BaseAlgorithm
|
|
57
|
+
from ...errors import InvalidParameterError
|
|
58
|
+
from ...registry import register_algorithm
|
|
59
|
+
from ...types import AlgorithmCategory, Spectrum1D, WorkContext
|
|
60
|
+
|
|
61
|
+
_SPEED_OF_LIGHT_KMS: float = 299792.458
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _resolve_jd_mid(spec: Spectrum1D) -> float | None:
|
|
65
|
+
"""Extract or derive the mid-exposure JD from the spectrum's meta."""
|
|
66
|
+
if spec.meta is None:
|
|
67
|
+
return None
|
|
68
|
+
jd_mid = spec.meta.get("jd_mid")
|
|
69
|
+
if jd_mid is not None:
|
|
70
|
+
return float(jd_mid)
|
|
71
|
+
dateobs = spec.meta.get("dateobs")
|
|
72
|
+
exptime = spec.meta.get("exptime_s")
|
|
73
|
+
if dateobs is None or exptime is None:
|
|
74
|
+
return None
|
|
75
|
+
try:
|
|
76
|
+
from astropy.time import Time # noqa: PLC0415 - astropy is heavy
|
|
77
|
+
except ImportError:
|
|
78
|
+
return None
|
|
79
|
+
try:
|
|
80
|
+
return float(Time(dateobs).jd + float(exptime) / 2.0 / 86400.0)
|
|
81
|
+
except Exception: # noqa: BLE001 - astropy raises a variety of types
|
|
82
|
+
return None
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _line_excess_on_velocity_grid(
|
|
86
|
+
spec: Spectrum1D, line_centre_aa: float, velocity_grid: np.ndarray,
|
|
87
|
+
) -> np.ndarray | None:
|
|
88
|
+
"""Resample the spectrum onto a velocity grid and subtract the continuum.
|
|
89
|
+
|
|
90
|
+
Returns ``intensity − 1`` (the line excess above unit continuum) or
|
|
91
|
+
``None`` if the input is too short / continuum non-positive.
|
|
92
|
+
"""
|
|
93
|
+
wave = np.asarray(spec.wavelength, dtype=np.float64)
|
|
94
|
+
flux = np.asarray(spec.flux, dtype=np.float64)
|
|
95
|
+
finite = np.isfinite(wave) & np.isfinite(flux)
|
|
96
|
+
if int(finite.sum()) < 30:
|
|
97
|
+
return None
|
|
98
|
+
wave = wave[finite]
|
|
99
|
+
flux = flux[finite]
|
|
100
|
+
velocity = _SPEED_OF_LIGHT_KMS * (wave - line_centre_aa) / line_centre_aa
|
|
101
|
+
intensity = np.interp(velocity_grid, velocity, flux, left=np.nan, right=np.nan)
|
|
102
|
+
n_edge = max(5, int(0.1 * intensity.size))
|
|
103
|
+
finite_int = np.isfinite(intensity)
|
|
104
|
+
if int(finite_int.sum()) < n_edge * 2:
|
|
105
|
+
return None
|
|
106
|
+
head_edge = intensity[finite_int][:n_edge]
|
|
107
|
+
tail_edge = intensity[finite_int][-n_edge:]
|
|
108
|
+
continuum = 0.5 * (float(np.median(head_edge)) + float(np.median(tail_edge)))
|
|
109
|
+
if continuum <= 0.0:
|
|
110
|
+
return None
|
|
111
|
+
return intensity / continuum - 1.0
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def _back_project(
|
|
115
|
+
trailed: np.ndarray, # (n_phases, n_velocity)
|
|
116
|
+
phases: np.ndarray, # (n_phases,)
|
|
117
|
+
velocity_grid: np.ndarray, # (n_velocity,)
|
|
118
|
+
gamma_kms: float,
|
|
119
|
+
n_velocity: int,
|
|
120
|
+
) -> np.ndarray:
|
|
121
|
+
"""Back-project the trailed spectrogram into the (V_x, V_y) plane."""
|
|
122
|
+
VX, VY = np.meshgrid(velocity_grid, velocity_grid, indexing="xy")
|
|
123
|
+
accumulator = np.zeros_like(VX, dtype=np.float64)
|
|
124
|
+
n_contrib = np.zeros_like(VX, dtype=np.float64)
|
|
125
|
+
|
|
126
|
+
for phase, row in zip(phases, trailed, strict=True):
|
|
127
|
+
phi = 2.0 * math.pi * float(phase)
|
|
128
|
+
v_proj = gamma_kms - VX * math.sin(phi) + VY * math.cos(phi)
|
|
129
|
+
# Resample the row onto v_proj; pixels with v_proj outside the
|
|
130
|
+
# velocity grid get NaN and are masked out of the average.
|
|
131
|
+
flat = np.interp(
|
|
132
|
+
v_proj.ravel(),
|
|
133
|
+
velocity_grid,
|
|
134
|
+
row,
|
|
135
|
+
left=np.nan,
|
|
136
|
+
right=np.nan,
|
|
137
|
+
).reshape(VX.shape)
|
|
138
|
+
valid = np.isfinite(flat)
|
|
139
|
+
accumulator[valid] += flat[valid]
|
|
140
|
+
n_contrib[valid] += 1.0
|
|
141
|
+
|
|
142
|
+
with np.errstate(invalid="ignore"):
|
|
143
|
+
out = np.where(n_contrib > 0.0, accumulator / n_contrib, 0.0)
|
|
144
|
+
return out
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
@register_algorithm(
|
|
148
|
+
"doppler_tomogram",
|
|
149
|
+
category=AlgorithmCategory.ADVANCED,
|
|
150
|
+
version="1.0.0",
|
|
151
|
+
)
|
|
152
|
+
class DopplerTomogram(BaseAlgorithm):
|
|
153
|
+
"""Doppler tomogram of a binary from N phase-resolved spectra.
|
|
154
|
+
|
|
155
|
+
Composes ``ctx.spectra`` (N ``Spectrum1D``, one per orbital phase)
|
|
156
|
+
into the ``(V_x, V_y)`` brightness map ``M`` by Marsh & Horne 1988
|
|
157
|
+
back-projection. Each input spectrum **must** carry its
|
|
158
|
+
mid-exposure timestamp in one of :
|
|
159
|
+
|
|
160
|
+
- ``spec.meta["jd_mid"]`` (preferred, no astropy dependency), OR
|
|
161
|
+
- ``spec.meta["dateobs"]`` + ``spec.meta["exptime_s"]`` (computed
|
|
162
|
+
with ``astropy.time.Time``).
|
|
163
|
+
|
|
164
|
+
Sits next to ``disentangle_sb2`` in the ``advanced`` category :
|
|
165
|
+
they share the binary-system focus but solve different problems —
|
|
166
|
+
disentangling produces two 1-D component spectra ; tomography
|
|
167
|
+
produces one 2-D velocity-space brightness map.
|
|
168
|
+
|
|
169
|
+
Outputs (under ``ctx.extras["tomography_result"]``) :
|
|
170
|
+
|
|
171
|
+
- ``velocity_grid_kms`` : (n_velocity,) symmetric grid.
|
|
172
|
+
- ``phase_grid`` : (n_spectra,) sorted phases.
|
|
173
|
+
- ``trailed_spectrogram`` : (n_phases, n_velocity) input intensity.
|
|
174
|
+
- ``doppler_map`` : (n_velocity, n_velocity) reconstructed M.
|
|
175
|
+
|
|
176
|
+
Companion bricks one could build later : ``doppler_tomogram_mem``
|
|
177
|
+
(Horne 1985) for sharper reconstructions, and a ``trailed_spectrum_view``
|
|
178
|
+
visualisation.
|
|
179
|
+
"""
|
|
180
|
+
|
|
181
|
+
backend = "numpy"
|
|
182
|
+
references = [
|
|
183
|
+
"Marsh & Horne 1988, MNRAS 235, 269 — Doppler tomography by "
|
|
184
|
+
"back-projection (§2).",
|
|
185
|
+
"Horne 1985, MNRAS 213, 129 — MEM tomographic reconstruction "
|
|
186
|
+
"(not implemented; cited for completeness).",
|
|
187
|
+
"Marsh 2001, Lecture Notes in Physics 573 — astrotomography review.",
|
|
188
|
+
]
|
|
189
|
+
long_description = (
|
|
190
|
+
"Back-projection of N phase-resolved spectra onto the (V_x, V_y) "
|
|
191
|
+
"plane. Pixels are averaged over the phases that contribute (NaN-"
|
|
192
|
+
"aware mean) so the phase-coverage footprint does not bleed into "
|
|
193
|
+
"the brightness map. JD_mid is read from each spectrum's "
|
|
194
|
+
"meta['jd_mid'], falling back to meta['dateobs'] + "
|
|
195
|
+
"meta['exptime_s'] via astropy.time.Time."
|
|
196
|
+
)
|
|
197
|
+
default_params: dict[str, Any] = {
|
|
198
|
+
"period_days": None,
|
|
199
|
+
"epoch_hjd": None,
|
|
200
|
+
"gamma_kms": 0.0,
|
|
201
|
+
"line_center_aa": 6562.82,
|
|
202
|
+
"velocity_window_kms": 1000.0,
|
|
203
|
+
"n_velocity": 121,
|
|
204
|
+
}
|
|
205
|
+
required_params = ["period_days", "epoch_hjd"]
|
|
206
|
+
param_descriptions = {
|
|
207
|
+
"period_days": "Orbital period of the binary (days).",
|
|
208
|
+
"epoch_hjd": "Reference epoch HJD of phase 0 (days).",
|
|
209
|
+
"gamma_kms": "Systemic velocity (km/s) added to the back-projection.",
|
|
210
|
+
"line_center_aa": "Rest wavelength (Å) of the line to tomogram.",
|
|
211
|
+
"velocity_window_kms": "Half-extent (km/s) of the V_x/V_y axes.",
|
|
212
|
+
"n_velocity": "Number of velocity samples per axis (odd, 11–401).",
|
|
213
|
+
}
|
|
214
|
+
input_requirements: list[str] = [] # validated dynamically
|
|
215
|
+
output_produces = ["extras.tomography_result", "metrics.n_spectra"]
|
|
216
|
+
|
|
217
|
+
def run(self, ctx: WorkContext, params: dict[str, Any]) -> AlgorithmOutput:
|
|
218
|
+
spectra = list(ctx.spectra or [])
|
|
219
|
+
if len(spectra) < 3:
|
|
220
|
+
return AlgorithmOutput.fail(
|
|
221
|
+
f"Need ≥ 3 spectra in ctx.spectra; got {len(spectra)}."
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
period = float(params["period_days"])
|
|
225
|
+
if period <= 0.0:
|
|
226
|
+
raise InvalidParameterError("period_days must be > 0.")
|
|
227
|
+
epoch_hjd = float(params["epoch_hjd"])
|
|
228
|
+
gamma_kms = float(params["gamma_kms"])
|
|
229
|
+
line_centre = float(params["line_center_aa"])
|
|
230
|
+
v_window = float(params["velocity_window_kms"])
|
|
231
|
+
if v_window <= 0.0:
|
|
232
|
+
raise InvalidParameterError("velocity_window_kms must be > 0.")
|
|
233
|
+
n_velocity = int(params["n_velocity"])
|
|
234
|
+
if not 11 <= n_velocity <= 401:
|
|
235
|
+
raise InvalidParameterError("n_velocity must be in [11, 401].")
|
|
236
|
+
|
|
237
|
+
velocity_grid = np.linspace(-v_window, +v_window, n_velocity)
|
|
238
|
+
|
|
239
|
+
rows: list[tuple[float, np.ndarray]] = []
|
|
240
|
+
skipped_no_jd = 0
|
|
241
|
+
skipped_bad_spec = 0
|
|
242
|
+
for spec in spectra:
|
|
243
|
+
jd_mid = _resolve_jd_mid(spec)
|
|
244
|
+
if jd_mid is None:
|
|
245
|
+
skipped_no_jd += 1
|
|
246
|
+
continue
|
|
247
|
+
excess = _line_excess_on_velocity_grid(spec, line_centre, velocity_grid)
|
|
248
|
+
if excess is None:
|
|
249
|
+
skipped_bad_spec += 1
|
|
250
|
+
continue
|
|
251
|
+
phase = ((jd_mid - epoch_hjd) / period) % 1.0
|
|
252
|
+
rows.append((float(phase), excess))
|
|
253
|
+
|
|
254
|
+
if len(rows) < 3:
|
|
255
|
+
return AlgorithmOutput.fail(
|
|
256
|
+
f"Only {len(rows)} usable spectra (need ≥ 3) — skipped "
|
|
257
|
+
f"{skipped_no_jd} for missing JD_mid and "
|
|
258
|
+
f"{skipped_bad_spec} for failed continuum / interpolation."
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
rows.sort(key=lambda row: row[0])
|
|
262
|
+
phases = np.asarray([row[0] for row in rows], dtype=np.float64)
|
|
263
|
+
trailed = np.stack([row[1] for row in rows], axis=0)
|
|
264
|
+
# NaN-aware: replace residual NaNs from np.interp by 0 before
|
|
265
|
+
# accumulation (they don't contribute, and "no data" ≠ "0 signal").
|
|
266
|
+
trailed_clean = np.where(np.isfinite(trailed), trailed, 0.0)
|
|
267
|
+
doppler_map = _back_project(
|
|
268
|
+
trailed_clean, phases, velocity_grid, gamma_kms, n_velocity,
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
result = {
|
|
272
|
+
"velocity_grid_kms": velocity_grid,
|
|
273
|
+
"phase_grid": phases,
|
|
274
|
+
"trailed_spectrogram": trailed,
|
|
275
|
+
"doppler_map": doppler_map,
|
|
276
|
+
"vx_axis_kms": velocity_grid,
|
|
277
|
+
"vy_axis_kms": velocity_grid,
|
|
278
|
+
"n_spectra": len(rows),
|
|
279
|
+
"n_skipped_no_jd": skipped_no_jd,
|
|
280
|
+
"n_skipped_bad_spec": skipped_bad_spec,
|
|
281
|
+
"period_days": period,
|
|
282
|
+
"epoch_hjd": epoch_hjd,
|
|
283
|
+
"gamma_kms": gamma_kms,
|
|
284
|
+
"line_center_aa": line_centre,
|
|
285
|
+
}
|
|
286
|
+
ctx.extras["tomography_result"] = result
|
|
287
|
+
ctx.metrics["n_spectra"] = float(len(rows))
|
|
288
|
+
ctx.metrics["period_days"] = period
|
|
289
|
+
ctx.metrics["epoch_hjd"] = epoch_hjd
|
|
290
|
+
ctx.metrics["gamma_kms"] = gamma_kms
|
|
291
|
+
ctx.metrics["line_center_aa"] = line_centre
|
|
292
|
+
return AlgorithmOutput.ok(
|
|
293
|
+
metrics={
|
|
294
|
+
"n_spectra": float(len(rows)),
|
|
295
|
+
"n_skipped_no_jd": float(skipped_no_jd),
|
|
296
|
+
"n_skipped_bad_spec": float(skipped_bad_spec),
|
|
297
|
+
"period_days": period,
|
|
298
|
+
"epoch_hjd": epoch_hjd,
|
|
299
|
+
"gamma_kms": gamma_kms,
|
|
300
|
+
"line_center_aa": line_centre,
|
|
301
|
+
},
|
|
302
|
+
artifacts={"tomography_result": result},
|
|
303
|
+
message=(
|
|
304
|
+
f"Doppler tomogram: {len(rows)} phase(s), "
|
|
305
|
+
f"V ∈ ±{v_window:.0f} km/s on {n_velocity}×{n_velocity} grid; "
|
|
306
|
+
f"peak |M| = {float(np.max(np.abs(doppler_map))):.3g}."
|
|
307
|
+
),
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
__all__ = ["DopplerTomogram"]
|