Skip to content
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

Improvement to spatial flexure #1870

Merged
merged 32 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
0e52afa
still nowhere
debora-pe Sep 17, 2024
aca3e44
Merge branch 'develop' into spatflex_improve
debora-pe Oct 22, 2024
a5c44b3
final version?
debora-pe Oct 29, 2024
b49a79a
some stuff for a QA plot
debora-pe Oct 30, 2024
f06bbd8
Merge branch 'develop' into spatflex_improve
debora-pe Nov 6, 2024
0a029a8
finalized QA plot
debora-pe Nov 8, 2024
c84e3e7
small fix
debora-pe Nov 8, 2024
e526c1e
small fix
debora-pe Nov 8, 2024
a447a20
improved
debora-pe Nov 8, 2024
dd06e5c
improved
debora-pe Nov 9, 2024
d286930
small fixes
debora-pe Nov 13, 2024
5cc3f32
docs
debora-pe Nov 13, 2024
3245c8c
docs
debora-pe Nov 13, 2024
617e550
Merge branch 'develop' into spatflex_improve
debora-pe Nov 13, 2024
d82cd5f
Merge branch 'release' into spatflex_improve
debora-pe Nov 13, 2024
3f3237d
added to release doc
debora-pe Nov 13, 2024
40cd1d4
forgot one parameters
debora-pe Nov 14, 2024
8ff7bda
Merge branch 'develop' into spatflex_improve
kbwestfall Nov 18, 2024
8cf8948
found a bug an fixed it
debora-pe Nov 19, 2024
9f05c66
fix the fix
debora-pe Nov 20, 2024
da9e7a1
small improv
debora-pe Nov 22, 2024
80676b4
Merge branch 'develop' into spatflex_improve
debora-pe Nov 22, 2024
279975d
small fix
debora-pe Nov 22, 2024
55b7a72
followed Ryan's suggestion
debora-pe Dec 5, 2024
df50e77
small thing
debora-pe Dec 5, 2024
9469cf4
small thing
debora-pe Dec 5, 2024
5dcddec
last comments
debora-pe Dec 10, 2024
9b233e1
Merge branch 'develop' into spatflex_improve
debora-pe Dec 13, 2024
da95545
Merge branch 'develop' into spatflex_improve
kbwestfall Dec 19, 2024
782162d
small fix
debora-pe Dec 20, 2024
18918ee
Merge branch 'spatflex_improve' of https://github.com/pypeit/PypeIt i…
debora-pe Dec 20, 2024
3e5a48e
Merge branch 'develop' into spatflex_improve
debora-pe Dec 20, 2024
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
78 changes: 40 additions & 38 deletions pypeit/core/flexure.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,56 +89,58 @@ def spat_flexure_shift(sciimg, slits, bpm=None, maxlag=20, sigdetect=10., debug=
_sciimg = sciimg if slitmask.shape == sciimg.shape \
else arc.resize_mask2arc(slitmask.shape, sciimg)

# create sobel images of both slitmask and the science image
sci_sobel, _ = trace.detect_slit_edges(_sciimg, bpm=bpm)
slits_sobel, _ = trace.detect_slit_edges(slitmask, bpm=bpm)
# collapse both sobel images along the spectral direction
sci_smash, _, _ = sigma_clipped_stats(sci_sobel, axis=0, mask=bpm)
# no need for sigma clipping for the slitmask
slits_smash = np.mean(slits_sobel, axis=0)
# remove nan values
sci_smash[np.isnan(sci_smash)] = 0
# invert the negative values
sci_smash[sci_smash < 0] *= -1
slits_smash[slits_smash < 0] *= -1

# create a synthetic "spectrum" of both slitmask and the science image for cross-correlation
corr_sci = wvutils.get_xcorr_arc(sci_smash, cont_sub=True, percent_ceil=10., sigdetect=sigdetect, debug=debug)
corr_slits = wvutils.get_xcorr_arc(slits_smash, cont_sub=False, percent_ceil=None, input_thresh=1., debug=debug)

if np.all(corr_sci == 0) or np.all(corr_slits == 0):
msgs.warn('No peak detected in the collapsed sobel images. Assuming there is NO SPATIAL FLEXURE.'
+ msgs.newline() + 'If a flexure is expected, consider either changing the '
'"spat_flexure_sigdetect" parameter, or use the manual flexure correction.')
return 0.
# run x-cross correlation
lags, xcorr = utils.cross_correlate(corr_sci, corr_slits, maxlag)
xcorr_denom = np.sqrt(np.sum(corr_sci*corr_sci)*np.sum(corr_slits*corr_slits))
xcorr_norm = xcorr / xcorr_denom
# mask (as much as possible) the objects on the slits to help the cross-correlation
# need to copy the bpm to avoid changing the input bpm
_bpm = np.zeros_like(_sciimg, dtype=int) if bpm is None else copy.deepcopy(bpm)
for i in range(slits.left_init.shape[1]):
Copy link
Collaborator

Choose a reason for hiding this comment

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

slits.nslits might be a little clearer

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

done

left_edge = slits.left_init[:, i].astype(int)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not a big deal, but should we do:
np.round(slits.left_init[:, i]).astype(int)
and likewise for right_edge?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

done

right_edge = slits.right_init[:, i].astype(int)
for j in range(_sciimg.shape[0]):
# mask the region between the left and right edges leaving a margin of maxlag pixels
if left_edge[j]+maxlag < right_edge[j]-maxlag:
_bpm[j, left_edge[j]+maxlag:right_edge[j]-maxlag] = 1

# # create sobel images of both slitmask and the science image
sci_sobel, sci_edges = trace.detect_slit_edges(_sciimg, bpm=_bpm, sigdetect=sigdetect)
slits_sobel, slits_edges = trace.detect_slit_edges(slitmask, bpm=bpm, sigdetect=1.)
corr = scipy.signal.fftconvolve(sci_edges, np.fliplr(slits_edges), mode='same', axes=1)
xcorr = np.sum(corr, axis=0)
lags = scipy.signal.correlation_lags(sci_edges.shape[1], slits_edges.shape[1], mode='same')
lag0 = np.where(lags == 0)[0][0]
xcorr_max = xcorr[lag0 - maxlag:lag0 + maxlag]
lags_max = lags[lag0 - maxlag:lag0 + maxlag]

# detect the highest peak in the cross-correlation
_, _, pix_max, _, _, _, _, _ = arc.detect_lines(xcorr_norm, cont_subtract=False, input_thresh=0.,
nfind=1, debug=debug)
_, _, pix_max, _, _, _, _, _ = arc.detect_lines(xcorr_max, cont_subtract=False, input_thresh=0., nfind=1, debug=debug)
# No peak? -- e.g. data fills the entire detector
if len(pix_max) == 0:
if (len(pix_max) == 0) or pix_max[0] == -999.0:
msgs.warn('No peak found in the x-correlation between the traced slits and the science/calib image.'
' Assuming there is NO SPATIAL FLEXURE.'+msgs.newline() + 'If a flexure is expected, '
'consider either changing the maximum lag for the cross-correlation, '
'or the "spat_flexure_sigdetect" parameter, or use the manual flexure correction.')

return 0.
lag0 = np.where(lags == 0)[0][0]
shift = round(pix_max[0] - lag0, 3)

lag0_max = np.where(lags_max == 0)[0][0]
shift = round(pix_max[0] - lag0_max, 3)
msgs.info('Spatial flexure measured: {}'.format(shift))

if debug:
# 1D plot
xvals = np.arange(corr_slits.size)
plt.figure(figsize=(9, 8))
scale = np.nanmax(corr_slits) / np.nanmax(corr_sci)
plt.suptitle(f'Shift={shift:.1f} pixels', fontsize=18)
plt.plot(xvals, corr_slits, 'k', label='slitmask edge peaks')
plt.plot(xvals, np.roll(scale*corr_sci, -int(shift)), '--r', label='shifted science edge peaks')
# 1D plot of the cross-correlation
plt.figure(figsize=(10, 6))
plt.minorticks_on()
plt.tick_params(axis='both', direction='in', top=True, right=True, which='both')
# plot xcorr_max but add a buffer of 20 pixels on each side
pad = 20
_xcorr_max = xcorr[lag0 - (maxlag+pad):lag0 + (maxlag+pad)]
_lags_max = lags[lag0 - (maxlag+pad):lag0 + (maxlag+pad)]
plt.plot(_lags_max, _xcorr_max, 'k-', lw=1)
plt.axvline(shift, color='r', linestyle='--', label=f'Measured shift = {shift:.1f} pixels')
plt.axvline(maxlag, color='g', linestyle='--', label='Max lag')
plt.axvline(-maxlag, color='g', linestyle='--')
plt.xlabel('Lag (pixels)')
plt.ylabel('Cross-correlation')
plt.title('Spatial Flexure Cross-correlation')
plt.legend()
plt.tight_layout()
plt.show()
Expand Down
11 changes: 5 additions & 6 deletions pypeit/par/pypeitpar.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,13 +365,12 @@ def __init__(self, trim=None, apply_gain=None, orient=None,
dtypes['spat_flexure_maxlag'] = int
descr['spat_flexure_maxlag'] = 'Maximum of possible spatial flexure correction, in pixels'

defaults['spat_flexure_sigdetect'] = 10.
defaults['spat_flexure_sigdetect'] = 5.
dtypes['spat_flexure_sigdetect'] = [int, float]
descr['spat_flexure_sigdetect'] = 'Sigma threshold above fluctuations for the slit detection in ' \
'the spectral image, for which the spatial flexure is computed. ' \
'A sobel filter is applied to the image and then collapsed along the ' \
'spectral direction. The sigma threshold is used to detect peaks in the '\
'collapsed image.'
descr['spat_flexure_sigdetect'] = 'Sigma threshold above fluctuations in the ' \
'Sobel-filtered significance image, used for ' \
'finding slit edges in the spectral image, ' \
'for which the spatial flexure is computed.'

defaults['spat_flexure_vrange'] = None
dtypes['spat_flexure_vrange'] = tuple
Expand Down
4 changes: 4 additions & 0 deletions pypeit/spectrographs/keck_lris.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@ def config_specific_par(self, scifile, inp_par=None):
# Arc lamps list from header
par['calibrations']['wavelengths']['lamps'] = ['use_header']

# spatial flexure maxshift for non-longslit
if 'long' not in self.get_meta_value(scifile, 'decker'):
par['scienceframe']['process']['spat_flexure_maxlag'] = 10

return par

def init_meta(self):
Expand Down
Loading