From fc10c989df78ffab26e78f3dbcfbde0694d7175f Mon Sep 17 00:00:00 2001 From: Debora Pelliccia Date: Tue, 5 May 2026 18:44:10 -1000 Subject: [PATCH 1/3] fix it --- pypeit/core/findobj_skymask.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/pypeit/core/findobj_skymask.py b/pypeit/core/findobj_skymask.py index a69b31d51e..88266dfe02 100644 --- a/pypeit/core/findobj_skymask.py +++ b/pypeit/core/findobj_skymask.py @@ -454,6 +454,7 @@ def ech_fill_in_orders(sobjs:specobjs.SpecObjs, slit_righ:np.ndarray, slit_spat_id: np.ndarray, order_vec:np.ndarray, + plate_scale_ord:np.ndarray, obj_id:np.ndarray, std_trace:table.Table=None, show:bool=False): @@ -493,6 +494,9 @@ def ech_fill_in_orders(sobjs:specobjs.SpecObjs, found. This is saved to the output :class:`~pypeit.specobj.SpecObj` objects. If the orders are not known, this can be ``np.arange(norders)`` (but this is *not* recommended). + plate_scale_ord (`numpy.ndarray`_): + An array with shape (norders,) providing the plate + scale of each order in arcsec/pix. obj_id (`numpy.ndarray`_): Object IDs of the objects linked together. std_trace (`astropy.table.Table`_, optional): @@ -642,13 +646,17 @@ def ech_fill_in_orders(sobjs:specobjs.SpecObjs, imin = np.argmin(np.abs(this_salign.ECH_ORDER - this_order)) # NOTE: when assigning FWHM, maskwidth, and BOX_R_PIX (in pixels) using the values # from the nearest detected order, for spectrographs with different platescale per order, - # these values will be different in arcseconds (which may not be a desirable approach). - thisobj.FWHM = this_salign[imin].FWHM + # these values will be different in arcseconds. Therefore, we need to convert these values + # using the plate scale of the nearest detected order and the plate scale of the current order. + indx = np.where(order_vec == this_salign[imin].ECH_ORDER)[0][0] + pscale_conv = plate_scale_ord[indx]/plate_scale_ord[iord] + + thisobj.FWHM = this_salign[imin].FWHM * pscale_conv thisobj.hand_extract_flag = this_salign[imin].hand_extract_flag - thisobj.maskwidth = this_salign[imin].maskwidth + thisobj.maskwidth = this_salign[imin].maskwidth * pscale_conv thisobj.smash_peakflux = this_salign[imin].smash_peakflux thisobj.smash_snr = this_salign[imin].smash_snr - thisobj.BOX_R_PIX = this_salign[imin].BOX_R_PIX + thisobj.BOX_R_PIX = this_salign[imin].BOX_R_PIX * pscale_conv thisobj.ECH_FRACPOS = uni_frac[iobj] thisobj.ECH_FRACPOS_ID = int(np.rint(1000*uni_frac[iobj])) thisobj.ECH_OBJID = uni_obj_id[iobj] @@ -1319,7 +1327,7 @@ def ech_objfind(image, ivar, slitmask, slit_left, slit_righ, slit_spat_id, order # Fill in Orders sobjs_filled = ech_fill_in_orders( - sobjs_in_orders, slit_left, slit_righ, slit_spat_id, order_vec, obj_id, std_trace=std_trace) + sobjs_in_orders, slit_left, slit_righ, slit_spat_id, order_vec, plate_scale, obj_id, std_trace=std_trace) # Cut on SNR and number of objects sobjs_pre_final = ech_cutobj_on_snr( From 6f6601c5d64244c705205464b6ada04bf989a9ae Mon Sep 17 00:00:00 2001 From: Debora Pelliccia Date: Mon, 18 May 2026 13:39:45 -1000 Subject: [PATCH 2/3] expose param to echelle reduction --- pypeit/core/findobj_skymask.py | 30 ++++++++++++++++++++++-------- pypeit/find_objects.py | 1 + 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/pypeit/core/findobj_skymask.py b/pypeit/core/findobj_skymask.py index bcd1d54b86..5131002195 100644 --- a/pypeit/core/findobj_skymask.py +++ b/pypeit/core/findobj_skymask.py @@ -169,8 +169,8 @@ def ech_findobj_ineach_order( order_vec, spec_min_max, plate_scale_ord, det='DET01', inmask=None, std_trace=None, ncoeff=5, hand_extract_dict=None, - box_radius=2.0, fwhm=3.0, - use_user_fwhm=False, maxdev=2.0, nperorder=2, numiterfit=9, + box_radius=2.0, fwhm=3.0,use_user_fwhm=False, + maxshift=1.0, maxdev=2.0, nperorder=2, numiterfit=9, extract_maskwidth=3.0, snr_thresh=10.0, specobj_dict=None, trim_edg=(5,5), show_peaks=False, show_single_fits=False, @@ -259,6 +259,9 @@ def ech_findobj_ineach_order( If True, ``PypeIt`` will use the spatial profile FWHM input by the user (see ``fwhm``) rather than determine the spatial FWHM from the smashed spatial profile via the automated algorithm. + maxshift (:obj:`float`, optional): + Maximum shift allowed between the input and recalculated + centroid (see :func:`~pypeit.core.trace.fit_trace`). maxdev (:obj:`float`, optional): Maximum deviation of pixels from polynomial fit to trace used to reject bad pixels in trace fitting. @@ -334,7 +337,7 @@ def ech_findobj_ineach_order( slit_left[:,iord], slit_righ[:,iord], spec_min_max=spec_min_max[:,iord], inmask=inmask_iord,std_trace=std_in, - ncoeff=ncoeff, fwhm=fwhm, use_user_fwhm=use_user_fwhm, maxdev=maxdev, + ncoeff=ncoeff, fwhm=fwhm, use_user_fwhm=use_user_fwhm, maxdev=maxdev, maxshift=maxshift, numiterfit=numiterfit, hand_extract_dict=hand_extract_dict, nperslit=nperorder, extract_maskwidth=extract_maskwidth, snr_thresh=snr_thresh, trim_edg=trim_edg, @@ -864,7 +867,8 @@ def ech_pca_traces( order_vec:np.ndarray, spec_min_max, npca:int=None, coeff_npoly:int=None, pca_explained_var:float=99.0, - ncoeff:int=5, maxdev:float=2.0, fwhm:float=3.0, + ncoeff:int=5, maxshift:float=1.0, + maxdev:float=2.0, fwhm:float=3.0, show_trace:bool=False, show_fits:bool=False, show_pca:bool=False): """ @@ -913,6 +917,11 @@ def ech_pca_traces( directly; see :func:`~pypeit.tracepca.pca_trace_object`. ncoeff (:obj:`int`, optional): Order of polynomial fit to traces. + maxshift (:obj:`float`, optional): + Maximum shift in pixels allowed between the original trace and the + new trace during the iterative flux-weighted centroiding. This is + used to prevent the traces from jumping to nearby objects during + the iterative flux-weighted centroiding. If None, no limit is applied. maxdev (:obj:`float`, optional): Maximum deviation of pixels from polynomial fit to trace used to reject bad pixels in trace fitting. @@ -976,13 +985,13 @@ def ech_pca_traces( inmask_now = inmask & allmask xfit_fweight = fit_trace(image, xinit_fweight, ncoeff, bpm=np.logical_not(inmask_now), trace_bpm=np.logical_not(trc_inmask), fwhm=fwhm, maxdev=maxdev, - debug=show_fits)[0] + maxshift=maxshift, debug=show_fits)[0] # Perform iterative Gaussian weighted centroiding xinit_gweight = xfit_fweight.copy() xfit_gweight = fit_trace(image, xinit_gweight, ncoeff, bpm=np.logical_not(inmask_now), trace_bpm=np.logical_not(trc_inmask), weighting='gaussian', fwhm=fwhm, - maxdev=maxdev, debug=show_fits)[0] + maxdev=maxdev, maxshift=maxshift, debug=show_fits)[0] #TODO Assign the new traces. Only assign the orders that were not orginally detected and traced. If this works # well, we will avoid doing all of the iter_tracefits above to make the code faster. @@ -1054,8 +1063,8 @@ def ech_objfind(image, ivar, slitmask, slit_left, slit_righ, slit_spat_id, order std_trace=None, ncoeff=5, npca=None, coeff_npoly=None, max_snr=2.0, min_snr=1.0, nabove_min_snr=2, pca_explained_var=99.0, - box_radius=2.0, fwhm=3.0, - use_user_fwhm=False, maxdev=2.0, + box_radius=2.0, fwhm=3.0, use_user_fwhm=False, + maxshift=1.0, maxdev=2.0, nperorder=2, numiterfit=9, extract_maskwidth=3.0, snr_thresh=10.0, specobj_dict=None, trim_edg=(5,5), @@ -1196,6 +1205,9 @@ def ech_objfind(image, ivar, slitmask, slit_left, slit_righ, slit_spat_id, order If True, ``PypeIt`` will use the spatial profile FWHM input by the user (see ``fwhm``) rather than determine the spatial FWHM from the smashed spatial profile via the automated algorithm. + maxshift (:obj:`float`, optional): + Maximum shift allowed between the input and recalculated + centroid (see :func:`~pypeit.core.trace.fit_trace`). maxdev (:obj:`float`, optional): Maximum deviation of pixels from polynomial fit to trace used to reject bad pixels in trace fitting. @@ -1309,6 +1321,7 @@ def ech_objfind(image, ivar, slitmask, slit_left, slit_righ, slit_spat_id, order fwhm=fwhm, use_user_fwhm=use_user_fwhm, nperorder=nperorder, + maxshift=maxshift, maxdev=maxdev, numiterfit=numiterfit, box_radius=box_radius, @@ -1353,6 +1366,7 @@ def ech_objfind(image, ivar, slitmask, slit_left, slit_righ, slit_spat_id, order coeff_npoly=coeff_npoly, ncoeff=ncoeff, npca=npca, pca_explained_var=pca_explained_var, + maxshift=maxshift, maxdev=maxdev, fwhm=fwhm, show_trace=show_trace, show_fits=show_fits, diff --git a/pypeit/find_objects.py b/pypeit/find_objects.py index b19346decf..a5f6195703 100644 --- a/pypeit/find_objects.py +++ b/pypeit/find_objects.py @@ -966,6 +966,7 @@ def find_objects_pypeline(self, image, ivar, std_trace=None, fwhm=self.par['reduce']['findobj']['find_fwhm'], use_user_fwhm=self.par['reduce']['extraction']['use_user_fwhm'], fof_link = self.par['reduce']['findobj']['fof_link'], + maxshift=self.par['reduce']['findobj']['trace_maxshift'], maxdev=self.par['reduce']['findobj']['trace_maxdev'], numiterfit=self.par['reduce']['findobj']['find_numiterfit'], nperorder=nperorder, From c2b1b482b92b9e1e626d7ca04534a3d0b6f9db42 Mon Sep 17 00:00:00 2001 From: Kyle Westfall Date: Mon, 1 Jun 2026 15:46:01 -0700 Subject: [PATCH 3/3] PR comments --- pypeit/core/findobj_skymask.py | 35 +++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/pypeit/core/findobj_skymask.py b/pypeit/core/findobj_skymask.py index 5131002195..cff1e8296d 100644 --- a/pypeit/core/findobj_skymask.py +++ b/pypeit/core/findobj_skymask.py @@ -232,8 +232,9 @@ def ech_findobj_ineach_order( predict the traces. If None, the minimum and maximum values will be determined automatically from ``slitmask``. plate_scale_ord (`numpy.ndarray`_): - An array with shape (norders,) providing the plate - scale of each order in arcsec/pix, + An array with shape (norders,) providing the plate scale of each + order in arcsec/pix. This is typically provided by + :func:`~pypeit.spectrographs.spectrograph.Spectrograph.order_platescale`. det (:obj:`str`, optional): The name of the detector containing the object. Only used if ``specobj_dict`` is None. @@ -260,8 +261,8 @@ def ech_findobj_ineach_order( user (see ``fwhm``) rather than determine the spatial FWHM from the smashed spatial profile via the automated algorithm. maxshift (:obj:`float`, optional): - Maximum shift allowed between the input and recalculated - centroid (see :func:`~pypeit.core.trace.fit_trace`). + Maximum shift [in pixels] allowed between the input and recalculated + trace centroid (see :func:`~pypeit.core.trace.fit_trace`). maxdev (:obj:`float`, optional): Maximum deviation of pixels from polynomial fit to trace used to reject bad pixels in trace fitting. @@ -337,7 +338,8 @@ def ech_findobj_ineach_order( slit_left[:,iord], slit_righ[:,iord], spec_min_max=spec_min_max[:,iord], inmask=inmask_iord,std_trace=std_in, - ncoeff=ncoeff, fwhm=fwhm, use_user_fwhm=use_user_fwhm, maxdev=maxdev, maxshift=maxshift, + ncoeff=ncoeff, fwhm=fwhm, use_user_fwhm=use_user_fwhm, maxdev=maxdev, + maxshift=maxshift, numiterfit=numiterfit, hand_extract_dict=hand_extract_dict, nperslit=nperorder, extract_maskwidth=extract_maskwidth, snr_thresh=snr_thresh, trim_edg=trim_edg, @@ -379,8 +381,9 @@ def ech_fof_sobjs(sobjs:specobjs.SpecObjs, Vector identifying the Echelle orders for each pair of order edges found. plate_scale_ord (`numpy.ndarray`_): - An array with shape (norders,) providing the plate - scale of each order in arcsec/pix, + An array with shape (norders,) providing the plate scale of each + order in arcsec/pix. This is typically provided by + :func:`~pypeit.spectrographs.spectrograph.Spectrograph.order_platescale`. fof_link (:obj:`float`, optional): Friends-of-friends linking length in arcseconds used to link together traces across orders. The routine links together at @@ -498,8 +501,9 @@ def ech_fill_in_orders(sobjs:specobjs.SpecObjs, objects. If the orders are not known, this can be ``np.arange(norders)`` (but this is *not* recommended). plate_scale_ord (`numpy.ndarray`_): - An array with shape (norders,) providing the plate - scale of each order in arcsec/pix. + An array with shape (norders,) providing the plate scale of each + order in arcsec/pix. This is typically provided by + :func:`~pypeit.spectrographs.spectrograph.Spectrograph.order_platescale`. obj_id (`numpy.ndarray`_): Object IDs of the objects linked together. std_trace (`astropy.table.Table`_, optional): @@ -726,8 +730,9 @@ def ech_cutobj_on_snr( order_vec (`numpy.ndarray`_): :obj:`int` array of good orders plate_scale_ord (`numpy.ndarray`_): - An array with shape (norders,) providing the plate - scale of each order in arcsec/pix, + An array with shape (norders,) providing the plate scale of each + order in arcsec/pix. This is typically provided by + :func:`~pypeit.spectrographs.spectrograph.Spectrograph.order_platescale`. max_snr (:obj:`float`, optional): For an object to be included in the output object, it must have a max S/N ratio above this value. @@ -1206,8 +1211,8 @@ def ech_objfind(image, ivar, slitmask, slit_left, slit_righ, slit_spat_id, order user (see ``fwhm``) rather than determine the spatial FWHM from the smashed spatial profile via the automated algorithm. maxshift (:obj:`float`, optional): - Maximum shift allowed between the input and recalculated - centroid (see :func:`~pypeit.core.trace.fit_trace`). + Maximum shift [in pixels] allowed between the input and recalculated + trace centroid (see :func:`~pypeit.core.trace.fit_trace`). maxdev (:obj:`float`, optional): Maximum deviation of pixels from polynomial fit to trace used to reject bad pixels in trace fitting. @@ -1792,8 +1797,8 @@ def objs_in_slit(image, ivar, thismask, slit_left, slit_righ, Box_car extraction radius *in pixels* to assign to each detected object and to be used later for boxcar extraction. maxshift (:obj:`float`, optional): - Maximum shift allowed between the input and recalculated - centroid (see :func:`~pypeit.core.trace.fit_trace`). + Maximum shift [in pixels] allowed between the input and recalculated + trace centroid (see :func:`~pypeit.core.trace.fit_trace`). maxdev (:obj:`float`, optional): Maximum deviation of pixels from polynomial fit to trace used to reject bad pixels in trace fitting.