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

Allow fwhm_fromlines for tilts calibration #1861

Merged
merged 8 commits into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
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
5 changes: 4 additions & 1 deletion pypeit/calibrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -1176,11 +1176,14 @@ def get_tilts(self):
_spat_flexure = self.mstilt.spat_flexure \
if self.par['tiltframe']['process']['spat_flexure_correct'] else None

# get measured fwhm from wv_calib
measured_fwhms = [wvfit.fwhm for wvfit in self.wv_calib.wv_fits]

# Build
buildwaveTilts = wavetilts.BuildWaveTilts(
self.mstilt, self.slits, self.spectrograph, self.par['tilts'],
self.par['wavelengths'], det=self.det, qa_path=self.qa_path,
spat_flexure=_spat_flexure)
spat_flexure=_spat_flexure, measured_fwhms=measured_fwhms)

# TODO still need to deal with syntax for LRIS ghosts. Maybe we don't need it
self.wavetilts = buildwaveTilts.run(doqa=self.write_qa, show=self.show)
Expand Down
7 changes: 4 additions & 3 deletions pypeit/par/pypeitpar.py
Original file line number Diff line number Diff line change
Expand Up @@ -2978,15 +2978,16 @@ def __init__(self, reference=None, method=None, echelle=None, ech_nspec_coeff=No
defaults['fwhm'] = 4.
dtypes['fwhm'] = [int, float]
descr['fwhm'] = 'Spectral sampling of the arc lines. This is the FWHM of an arcline in ' \
'binned pixels of the input arc image'
'binned pixels of the input arc image. Note that this is used also in the ' \
'wave tilts calibration.'

defaults['fwhm_fromlines'] = True
dtypes['fwhm_fromlines'] = bool
descr['fwhm_fromlines'] = 'Estimate spectral resolution in each slit using the arc lines. '\
'If True, the estimated FWHM will override ``fwhm`` only in '\
'If True, the estimated FWHM will override ``fwhm`` in '\
'the determination of the wavelength solution (including the ' \
'calculation of the threshold for the solution RMS, see ' \
'``rms_thresh_frac_fwhm``), but not for the wave tilts calibration.' \
'``rms_thresh_frac_fwhm``), and ALSO for the wave tilts calibration.' \

defaults['fwhm_spat_order'] = 0
dtypes['fwhm_spat_order'] = int
Expand Down
8 changes: 6 additions & 2 deletions pypeit/scripts/chk_tilts.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,18 @@ def get_parser(cls, width=None):

@staticmethod
def main(args):
from pathlib import Path
from pypeit import wavetilts

chk_version = not args.try_old

# tilts file path
file = Path(args.file).absolute()

# Load
tilts = wavetilts.WaveTilts.from_file(args.file, chk_version=chk_version)
tilts = wavetilts.WaveTilts.from_file(file, chk_version=chk_version)
tilts.show(in_ginga=np.logical_not(args.mpl), show_traces=args.show_traces,
chk_version=chk_version)
calib_dir=file.parent, chk_version=chk_version)



84 changes: 59 additions & 25 deletions pypeit/wavetilts.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from pypeit.display import display
from pypeit.core import arc
from pypeit.core import tracewave
from pypeit.core.wavecal import autoid
from pypeit.images import buildimage


Expand Down Expand Up @@ -174,7 +175,7 @@ def spatid_to_zero(self, spat_id):
return np.where(mtch)[0][0]

def show(self, waveimg=None, wcs_match=True, in_ginga=True, show_traces=False,
chk_version=True):
calib_dir=None, chk_version=True):
"""
Show in ginga or mpl Tiltimg with the tilts traced and fitted overlaid

Expand All @@ -188,22 +189,32 @@ def show(self, waveimg=None, wcs_match=True, in_ginga=True, show_traces=False,
If True, show the image in ginga. Otherwise, use matplotlib.
show_traces (bool, optional):
If True, show the traces of the tilts on the image.
calib_dir (`Path`_):
Path to the calibration directory. If None, the path is taken from the
WaveTilts object.
chk_version (:obj:`bool`, optional):
When reading in existing files written by PypeIt, perform strict
version checking to ensure a valid file. If False, the code
will try to keep going, but this may lead to faults and quiet
failures. User beware!
"""
# get tilt_img_dict
cal_file = Path(self.calib_dir).absolute() / self.tiltimg_filename
_calib_dir = self.calib_dir
if calib_dir is not None and calib_dir.exists():
_calib_dir = calib_dir
msgs.info(f'Searching for other calibration files in {str(_calib_dir)}')
else:
msgs.info(f'Searching for other calibration files in the default directory {str(_calib_dir)}')

cal_file = Path(_calib_dir).absolute() / self.tiltimg_filename
if cal_file.exists():
tilt_img_dict = buildimage.TiltImage.from_file(cal_file, chk_version=chk_version)
else:
msgs.error(f'Tilt image {str(cal_file)} NOT FOUND.')

# get slits
slitmask = None
cal_file = Path(self.calib_dir).absolute() / self.slits_filename
cal_file = Path(_calib_dir).absolute() / self.slits_filename
if cal_file.exists():
slits = slittrace.SlitTraceSet.from_file(cal_file, chk_version=chk_version)
_slitmask = slits.slit_img(initial=True, flexure=self.spat_flexure)
Expand All @@ -220,7 +231,7 @@ def show(self, waveimg=None, wcs_match=True, in_ginga=True, show_traces=False,
# get waveimg
same_size = (slits.nspec, slits.nspat) == tilt_img_dict.image.shape
if waveimg is None and slits is not None and same_size and in_ginga:
wv_calib_name = wavecalib.WaveCalib.construct_file_name(self.calib_key, calib_dir=self.calib_dir)
wv_calib_name = wavecalib.WaveCalib.construct_file_name(self.calib_key, calib_dir=_calib_dir)
if Path(wv_calib_name).absolute().exists():
wv_calib = wavecalib.WaveCalib.from_file(wv_calib_name, chk_version=chk_version)
tilts = self.fit2tiltimg(slitmask, flexure=self.spat_flexure)
Expand Down Expand Up @@ -268,24 +279,32 @@ class BuildWaveTilts:
slits (:class:`~pypeit.slittrace.SlitTraceSet`):
Slit edges
spectrograph (:class:`~pypeit.spectrographs.spectrograph.Spectrograph`):
Spectrograph object
The `Spectrograph` instance that sets the instrument used. Used to set
Copy link
Collaborator

Choose a reason for hiding this comment

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

thx for polishing these!

:attr:`spectrograph`.
par (:class:`~pypeit.par.pypeitpar.WaveTiltsPar` or None):
The parameters used to fuss with the tilts
The parameters used for the tilt calibration.
Uses ``['calibrations']['tilts']``.
wavepar (:class:`~pypeit.par.pypeitpar.WavelengthSolutionPar` or None):
The parameters used for the wavelength solution
det (int): Detector index
The parameters used for the wavelength solution.
Uses ``['calibrations']['wavelengths']``.
det (int):
Detector index
qa_path (:obj:`str`, optional):
Directory for QA output.
spat_flexure (float, optional):
If input, the slitmask and slit edges are shifted prior
to tilt analysis.
measured_fwhms (`numpy.ndarray`_, optional):
FWHM of the arc lines measured during wavecalib. If provided, this
will be used for arc/sky line detection.



Attributes:
spectrograph (:class:`~pypeit.spectrographs.spectrograph.Spectrograph`):
??
The `Spectrograph` instance that sets the instrument used.
steps (list):
??
List of the processing steps performed
mask (`numpy.ndarray`_):
boolean array; True = Ignore this slit
all_trcdict (list):
Expand All @@ -304,7 +323,7 @@ class BuildWaveTilts:

# TODO This needs to be modified to take an inmask
def __init__(self, mstilt, slits, spectrograph, par, wavepar, det=1, qa_path=None,
spat_flexure=None):
spat_flexure=None, measured_fwhms=None):

# TODO: Perform type checking
self.spectrograph = spectrograph
Expand All @@ -316,6 +335,7 @@ def __init__(self, mstilt, slits, spectrograph, par, wavepar, det=1, qa_path=Non
self.det = det
self.qa_path = qa_path
self.spat_flexure = spat_flexure
self.measured_fwhms = measured_fwhms if measured_fwhms is not None else np.array([None] * slits.nslits)

# Get the non-linear count level
if self.mstilt.is_mosaic:
Expand Down Expand Up @@ -385,23 +405,26 @@ def extract_arcs(self):

return arccen, arccen_bpm

def find_lines(self, arcspec, slit_cen, slit_idx, bpm=None, debug=False):
def find_lines(self, arcspec, slit_cen, slit_idx, fwhm, bpm=None, debug=False):
"""
Find the lines for tracing

Wrapper to tracewave.tilts_find_lines()

Args:
arcspec ():
??
slit_cen ():
??
arcspec (`numpy.ndarray`_):
1D spectrum to be searched for significant detections.
slit_cen (`numpy.ndarray`_):
Trace down the center of the slit. Must match the shape of arcspec.
slit_idx (int):
Slit index, zero-based
Slit index, zero-based.
fwhm (float):
FWHM of the arc lines.
bpm (`numpy.ndarray`_, optional):
??
Bad-pixel mask for input spectrum. If None, all pixels considered good.
If passed, must match the shape of arcspec.
debug (bool, optional):
??
Show a QA plot for the line detection.

Returns:
tuple: 2 objectcs
Expand All @@ -423,7 +446,7 @@ def find_lines(self, arcspec, slit_cen, slit_idx, bpm=None, debug=False):
sig_neigh=self.par['sig_neigh'],
nfwhm_neigh=self.par['nfwhm_neigh'],
only_these_lines=only_these_lines,
fwhm=self.wavepar['fwhm'],
fwhm=fwhm,
nonlinear_counts=self.nonlinear_counts,
bpm=bpm, debug_peaks=False, debug_lines=debug)

Expand Down Expand Up @@ -478,7 +501,7 @@ def fit_tilts(self, trc_tilt_dict, thismask, slit_cen, spat_order, spec_order, s
self.steps.append(inspect.stack()[0][3])
return self.all_fit_dict[slit_idx]['coeff2']

def trace_tilts(self, arcimg, lines_spec, lines_spat, thismask, slit_cen,
def trace_tilts(self, arcimg, lines_spec, lines_spat, thismask, slit_cen, fwhm,
debug_pca=False, show_tracefits=False):
"""
Trace the tilts
Expand All @@ -500,14 +523,20 @@ def trace_tilts(self, arcimg, lines_spec, lines_spat, thismask, slit_cen,
is (nspec, nspat) with dtype=bool.
slit_cen (:obj:`int`):
Integer index indicating the slit in question.
fwhm (:obj:`float`):
FWHM of the arc lines.
debug_pca (:obj:`bool`, optional):
Show the PCA modeling QA plots.
show_tracefits (:obj:`bool`, optional):
Show the trace fits.

Returns:
dict: Dictionary containing information on the traced tilts required
to fit the filts.

"""
trace_dict = tracewave.trace_tilts(arcimg, lines_spec, lines_spat, thismask, slit_cen,
inmask=self.gpm, fwhm=self.wavepar['fwhm'],
inmask=self.gpm, fwhm=fwhm,
spat_order=self.par['spat_order'],
maxdev_tracefit=self.par['maxdev_tracefit'],
sigrej_trace=self.par['sigrej_trace'],
Expand Down Expand Up @@ -561,11 +590,13 @@ def model_arc_continuum(self, debug=False):
for i in range(nslits):
if self.tilt_bpm[i]:
continue
# get FWHM for this slit
fwhm = autoid.set_fwhm(self.wavepar, measured_fwhm=self.measured_fwhms[i])
# TODO: What to do with the following iter_continuum parameters?:
# sigthresh, sigrej, niter_cont, cont_samp, cont_frac_fwhm
arc_continuum[:,i], arc_fitmask[:,i] \
= arc.iter_continuum(self.arccen[:,i], gpm=np.invert(self.arccen_bpm[:,i]),
fwhm=self.wavepar['fwhm'])
fwhm=fwhm)
# TODO: Original version. Please leave it for now.
# arc_fitmask[:,i], coeff \
# = utils.robust_polyfit_djs(spec, self.arccen[:,i], self.par['cont_order'],
Expand Down Expand Up @@ -677,6 +708,7 @@ def run(self, doqa=True, debug=False, show=False):
# Subtract arc continuum
_mstilt = self.mstilt.image.copy()
if self.par['rm_continuum']:
msgs.info('Subtracting the continuum')
continuum = self.model_arc_continuum(debug=debug)
_mstilt -= continuum
if debug:
Expand Down Expand Up @@ -713,11 +745,13 @@ def run(self, doqa=True, debug=False, show=False):
self.slits.mask[slit_idx] = self.slits.bitmask.turn_on(self.slits.mask[slit_idx], 'BADTILTCALIB')
continue
msgs.info(f'Computing tilts for slit/order {self.slits.slitord_id[slit_idx]} ({slit_idx+1}/{self.slits.nslits})')
# Get the arc FWHM for this slit
fwhm = autoid.set_fwhm(self.wavepar, measured_fwhm=self.measured_fwhms[slit_idx], verbose=True)
# Identify lines for tracing tilts
msgs.info('Finding lines for tilt analysis')
self.lines_spec, self.lines_spat \
= self.find_lines(self.arccen[:,slit_idx], self.slitcen[:,slit_idx],
slit_idx,
slit_idx, fwhm,
bpm=self.arccen_bpm[:,slit_idx], debug=debug)

if self.lines_spec is None:
Expand All @@ -733,7 +767,7 @@ def run(self, doqa=True, debug=False, show=False):
# each line.
msgs.info('Trace the tilts')
self.trace_dict = self.trace_tilts(_mstilt, self.lines_spec, self.lines_spat,
thismask, self.slitcen[:, slit_idx])
thismask, self.slitcen[:, slit_idx], fwhm)
# IF there are < 2 usable arc lines for tilt tracing, PCA fit does not work and the reduction crushes
# TODO investigate why some slits have <2 usable arc lines
if np.sum(self.trace_dict['use_tilt']) < 2:
Expand Down
Loading