Skip to content

Implement 1D wavelength calibration classes #162

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 31 commits into from
Apr 12, 2023
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
d58f652
Working on line pixel refinement
rosteen Jan 18, 2023
1f3483a
Testing/debugging CalibrationLine, starting on WavelengthCalibration
rosteen Jan 19, 2023
c54aed7
Working on model fitting and construction of resulting GWCS
rosteen Jan 26, 2023
5eb4aaa
Working through bugs/testing
rosteen Jan 26, 2023
baa706c
Working initial implementation
rosteen Jan 26, 2023
02ed67e
Codestyle
rosteen Jan 26, 2023
1df8621
Match order of pixel/wavelength between CalibrationLine and Wavelengt…
rosteen Jan 27, 2023
eb5feea
Fix codestyle in test
rosteen Jan 27, 2023
6ea98e4
Adding tests for CalibrationLine
rosteen Jan 31, 2023
af4a523
Fix codestlye
rosteen Jan 31, 2023
568fd09
Increase atol for gaussian center
rosteen Jan 31, 2023
be35c09
Remove autoidentify for now, add Polynomial1D test
rosteen Feb 1, 2023
f3b1b9f
Add cache clearing, avoid AstropyUserWarning
rosteen Feb 1, 2023
8117864
Add input_spectrum property and clear cache on setting it
rosteen Feb 1, 2023
8f1535b
Add default range if method is set but not range, remove check for un…
rosteen Feb 2, 2023
22e2d68
Also clear cache when updating lines or model
rosteen Feb 3, 2023
4a508e3
Move fitter default to wcs call
rosteen Feb 3, 2023
a8ca23f
Keep storing fitter as None
rosteen Feb 3, 2023
1941a26
Add docs, improve importing of new classes
rosteen Feb 7, 2023
829dc5c
Remove CalibrationLine, move to astropy tables internallyt
rosteen Apr 6, 2023
c3ba30d
Codestyle
rosteen Apr 6, 2023
62c8025
Apply suggestions from code review
rosteen Apr 7, 2023
12a8661
Remove speactral_units arg, add docstring for fitter arg
rosteen Apr 7, 2023
5063b5e
Update documentation, add NotImplementedError for catalog input
rosteen Apr 7, 2023
b6a92f8
Reverse sort frequencies
rosteen Apr 7, 2023
1aa62c6
Codestyle
rosteen Apr 7, 2023
7f31b61
Increase test coverage
rosteen Apr 10, 2023
45939a9
Fix tests and bugs found by tests
rosteen Apr 10, 2023
f92bac5
Codestyle
rosteen Apr 10, 2023
d573219
Add QTable to catalog options
rosteen Apr 10, 2023
82170a5
Finish addressing review comments
rosteen Apr 11, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions specreduce/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
import os

from astropy.version import version as astropy_version
import astropy.units as u
import numpy as np
import pytest
from specutils import Spectrum1D

# For Astropy 3.0 and later, we can use the standalone pytest plugin
if astropy_version < '3.0':
Expand All @@ -20,6 +24,37 @@
ASTROPY_HEADER = False


@pytest.fixture
def spec1d():
np.random.seed(7)
flux = np.random.random(50)*u.Jy
sa = np.arange(0, 50)*u.pix
spec = Spectrum1D(flux, spectral_axis=sa)
return spec


@pytest.fixture
def spec1d_with_emission_line():
np.random.seed(7)
sa = np.arange(0, 200)*u.pix
flux = (np.random.randn(200) +
10*np.exp(-0.01*((sa.value-130)**2)) +
sa.value/100) * u.Jy
spec = Spectrum1D(flux, spectral_axis=sa)
return spec


@pytest.fixture
def spec1d_with_absorption_line():
np.random.seed(7)
sa = np.arange(0, 200)*u.pix
flux = (np.random.randn(200) -
10*np.exp(-0.01*((sa.value-130)**2)) +
sa.value/100) * u.Jy
spec = Spectrum1D(flux, spectral_axis=sa)
return spec


Comment on lines +27 to +57
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would this benefit from using the synthetic spectra from #165?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but I think using that to expand/improve the tests can be another PR once both of these are merged.

def pytest_configure(config):

if ASTROPY_HEADER:
Expand Down
69 changes: 69 additions & 0 deletions specreduce/tests/test_wavelength_calibration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
from numpy.testing import assert_allclose

import astropy.units as u
from astropy.modeling.models import Polynomial1D
from astropy.tests.helper import assert_quantity_allclose

from specreduce.wavelength_calibration import CalibrationLine, WavelengthCalibration1D


def test_linear_from_list(spec1d):
test = WavelengthCalibration1D(spec1d, [(5000*u.AA, 0), (5100*u.AA, 10),
(5198*u.AA, 20), (5305*u.AA, 30)])
spec2 = test.apply_to_spectrum(spec1d)

assert_quantity_allclose(spec2.spectral_axis[0], 4998.8*u.AA)
assert_quantity_allclose(spec2.spectral_axis[-1], 5495.169999*u.AA)


def test_linear_from_calibrationline(spec1d):
lines = [CalibrationLine(spec1d, 5000*u.AA, 0), CalibrationLine(spec1d, 5100*u.AA, 10),
CalibrationLine(spec1d, 5198*u.AA, 20), CalibrationLine(spec1d, 5305*u.AA, 30)]
test = WavelengthCalibration1D(spec1d, lines)
spec2 = test.apply_to_spectrum(spec1d)

assert_quantity_allclose(spec2.spectral_axis[0], 4998.8*u.AA)
assert_quantity_allclose(spec2.spectral_axis[-1], 5495.169999*u.AA)


def test_poly_from_calibrationline(spec1d):
# This test is mostly to prove that you can use other models
lines = [CalibrationLine(spec1d, 5005*u.AA, 0), CalibrationLine(spec1d, 5110*u.AA, 10),
CalibrationLine(spec1d, 5214*u.AA, 20), CalibrationLine(spec1d, 5330*u.AA, 30),
CalibrationLine(spec1d, 5438*u.AA, 40)]
test = WavelengthCalibration1D(spec1d, lines, model=Polynomial1D(2))
test.apply_to_spectrum(spec1d)

assert_allclose(test.model.parameters, [5.00477143e+03, 1.03457143e+01, 1.28571429e-02])


def test_calibrationline(spec1d_with_emission_line, spec1d_with_absorption_line):

line = CalibrationLine(spec1d_with_emission_line, 5000*u.AA, 128, refinement_method='gaussian',
refinement_kwargs={'range': 25})
assert_allclose(line.refine(), 129.44371, atol=0.01)

line2 = CalibrationLine(spec1d_with_emission_line, 5000*u.AA, 130, refinement_method='max',
refinement_kwargs={'range': 10})
assert line2.refine() == 128

line3 = CalibrationLine(spec1d_with_absorption_line, 5000*u.AA, 128, refinement_method='min',
refinement_kwargs={'range': 10})
assert line3.refine() == 130


def test_replace_spectrum(spec1d, spec1d_with_emission_line):
lines = [CalibrationLine(spec1d, 5000*u.AA, 0), CalibrationLine(spec1d, 5100*u.AA, 10),
CalibrationLine(spec1d, 5198*u.AA, 20), CalibrationLine(spec1d, 5305*u.AA, 30)]
test = WavelengthCalibration1D(spec1d, lines)
# Accessing this property causes fits the model and caches the resulting WCS
test.wcs
assert "wcs" in test.__dict__
for line in test.lines:
assert "refined_pixel" in line.__dict__

# Replace the input spectrum, which should clear the cached properties
test.input_spectrum = spec1d_with_emission_line
assert "wcs" not in test.__dict__
for line in test.lines:
assert "refined_pixel" not in line.__dict__
Loading