Skip to content

Commit fd00b76

Browse files
committed
LSF works
1 parent 540900e commit fd00b76

2 files changed

Lines changed: 69 additions & 8 deletions

File tree

scopesim/effects/metis_ifu_simple/ifu_simple.py

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,16 @@
33

44
from typing import ClassVar
55

6+
import numpy as np
7+
from astropy.convolution import convolve, Box1DKernel, Gaussian1DKernel
8+
69
from ..effects import Effect
710
from ...optics.fov import FieldOfView
811
from ...utils import from_currsys, get_logger
912

1013
logger = get_logger(__name__)
1114

15+
1216
class LineSpreadFunction(Effect):
1317
"""
1418
Compute and apply line spread function to IFU cube
@@ -26,13 +30,52 @@ def __init__(self, **kwargs):
2630
self.meta.update(kwargs)
2731
self.meta = from_currsys(self.meta, self.cmds)
2832

29-
self.lsfwidth = None #self.get_width()
30-
self.kernel = None #self.get_kernel()
33+
if "lsfwidth" not in self.meta:
34+
self.lsfwidth = self.get_lsf_width()
35+
else:
36+
self.lsfwidth = self.meta["lsfwidth"]
37+
self.kernel = self.get_kernel()
3138

32-
def apply_to(self, obj, **kwargs):
39+
def apply_to(self, fov, **kwargs):
3340
"""Apply the LSF"""
34-
if not isinstance(obj, FieldOfView):
35-
return obj
41+
if not isinstance(fov, FieldOfView):
42+
return fov
43+
44+
if fov.hdu is None or fov.hdu.header["NAXIS"] != 3:
45+
logger.error("Cannot apply LSF convolution")
46+
return fov
47+
48+
49+
print("Happily convolving with LSF")
50+
fov.hdu.data = convolve(fov.hdu.data, self.kernel)
51+
fov.cube = fov.hdu
52+
return fov
53+
54+
def get_lsf_width(self):
55+
"""Determine width of the LSF kernel at central wavelength"""
56+
57+
slope = self.meta['fit_slope']
58+
intercept = self.meta['fit_intercept']
59+
lamc = self.meta["wavelen"]
60+
dlam_per_pix = slope * lamc + intercept
61+
62+
slice_width = self.meta['slice_width']
63+
pixel_scale = self.meta['pixel_scale']
64+
65+
dlam_per_slice = dlam_per_pix * slice_width / pixel_scale
66+
67+
spec_binwidth = self.meta["spec_binwidth"]
68+
69+
return dlam_per_slice / spec_binwidth
70+
71+
72+
def get_kernel(self):
73+
"""Build LSF kernel: box kernel smoothed with narrow Gauss"""
3674

37-
lamc = from_currsys("!OBS.wavelen", self.cmds)
38-
print(">>>>>>>>> Central wavelength:", lamc)
75+
box = Box1DKernel(width=self.lsfwidth)
76+
gauss = Gaussian1DKernel(1)
77+
if box.shape > gauss.shape:
78+
kernel = convolve(box.array, gauss)[np.newaxis, np.newaxis, :]
79+
else:
80+
kernel = convolve(gauss.array, box)[np.newaxis, np.newaxis, :]
81+
return kernel

scopesim/tests/tests_effects/test_MetisIfuSimple.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,26 @@
44
# pylint: disable=missing-class-docstring
55
# pylint: disable=missing-function-docstring
66

7+
import pytest
8+
import numpy as np
79
from scopesim.effects.metis_ifu_simple import LineSpreadFunction
810

911
class TestLineSpreadFunction:
1012
def test_initialises_correctly(self):
11-
assert isinstance(LineSpreadFunction(), LineSpreadFunction)
13+
assert isinstance(LineSpreadFunction(lsfwidth=2.7), LineSpreadFunction)
14+
15+
@pytest.mark.parametrize("width", [1.5, 2.7, 3.0, 5.2])
16+
def test_kernel_is_normalised(self, width):
17+
lsf = LineSpreadFunction(lsfwidth=width)
18+
assert np.isclose(lsf.kernel.sum(), 1, 0.02)
19+
20+
21+
def test_kernel_is_normalised_with_params(self):
22+
lsf = LineSpreadFunction(wavelen=3.0,
23+
fit_slope=3.795e-6,
24+
fit_intercept=-4.659e-7,
25+
slice_width=0.0207,
26+
pixel_scale=0.0082,
27+
spec_binwidth=1e-5)
28+
assert isinstance(lsf, LineSpreadFunction)
29+
assert np.isclose(lsf.kernel.sum(), 1, 1e-4)

0 commit comments

Comments
 (0)