コード例 #1
0
ファイル: wvutils.py プロジェクト: legolason/PypeIt
def smooth_ceil_cont(inspec1, smooth, percent_ceil = None, use_raw_arc=False,sigdetect = 10.0, fwhm = 4.0):
    """ Utility routine to smooth and apply a ceiling to spectra """

    # ToDO can we improve the logic here. Technically if use_raw_arc = True and perecent_ceil=None
    # we don't need to peak find or continuum subtract, but this makes the code pretty uggly.

    # Run line detection to get the continuum subtracted arc
    tampl1, tampl1_cont, tcent1, twid1, centerr1, w1, arc1, nsig1 = arc.detect_lines(inspec1, sigdetect=sigdetect, fwhm=fwhm)
    if use_raw_arc == True:
        ampl = tampl1
        use_arc = inspec1
    else:
        ampl = tampl1_cont
        use_arc = arc1

    if percent_ceil is not None and (ampl.size > 0):
        # If this is set, set a ceiling on the greater > 10sigma peaks
        ceil1 = np.percentile(ampl, percent_ceil)
        spec1 = np.fmin(use_arc, ceil1)
    else:
        spec1 = np.copy(use_arc)

    if smooth is not None:
        y1 = scipy.ndimage.filters.gaussian_filter(spec1, smooth)
    else:
        y1 = np.copy(spec1)

    return y1
コード例 #2
0
def test_flex_shift():
    # Dummy slf
    # Read spectra
    obj_spec = readspec(data_path('obj_lrisb_600_sky.fits'))
    arx_file = os.path.join(data.Paths.sky_spec, 'sky_LRISb_600.fits')
    arx_spec = readspec(arx_file)
    arx_lines = arc.detect_lines(arx_spec.flux.value)

    # Call
    flex_dict = flexure.spec_flex_shift(obj_spec,
                                        arx_spec,
                                        arx_lines,
                                        mxshft=60)

    #    # Apply
    #    from scipy import interpolate
    #    print(flex_dict['shift'])
    #    npix = len(obj_spec.wavelength)
    #    x = np.linspace(0., 1., npix)
    #    f = interpolate.interp1d(x, obj_spec.wavelength.value, bounds_error=False,
    #                             fill_value="extrapolate")
    #    new_wave = f(x+flex_dict['shift']/(npix-1))
    #
    #    from matplotlib import pyplot
    #    pyplot.plot(arx_spec.wavelength, arx_spec.flux)
    #    pyplot.plot(obj_spec.wavelength, obj_spec.flux)
    #    pyplot.plot(new_wave, obj_spec.flux)
    #    pyplot.show()
    assert np.abs(flex_dict['shift'] - 43.7) < 0.1
コード例 #3
0
def xcorr_shift(inspec1,inspec2,smooth = None,debug = False):

    if smooth is not None:
        y1 = scipy.ndimage.filters.gaussian_filter(inspec1, smooth)
        y2 = scipy.ndimage.filters.gaussian_filter(inspec2, smooth)
    else:
        y1 = inspec1
        y2 = inspec2

    nspec = y1.shape[0]
    lags = np.arange(-nspec + 1, nspec)
    corr = scipy.signal.correlate(y1, y2, mode='full')
    corr_denom = np.sqrt(np.sum(y1*y1)*np.sum(y2*y2))
    corr_norm = corr/corr_denom
    output = arc.detect_lines(corr_norm, nfitpix=7, sigdetect=5.0, fwhm=20.0, mask_width = 10.0, cont_samp=30, nfind = 1)
    pix_max = output[1]
    corr_max = np.interp(pix_max, np.arange(lags.shape[0]),corr_norm)
    lag_max  = np.interp(pix_max, np.arange(lags.shape[0]),lags)
    if debug:
        # Interpolate for bad lines since the fitting code often returns nan
        plt.figure(figsize=(14, 6))
        plt.plot(lags, corr_norm, color='black', drawstyle = 'steps-mid', lw=3, label = 'x-corr', linewidth = 1.0)
        plt.plot(lag_max[0], corr_max[0],'g+', markersize =6.0, label = 'peak')
        plt.title('Best shift = {:5.3f}'.format(lag_max[0]) + ',  corr_max = {:5.3f}'.format(corr_max[0]))
        plt.legend()
        plt.show()

    return lag_max[0], corr_max[0]
コード例 #4
0
ファイル: test_arc.py プロジェクト: seib2/PypeIt
def test_detect_lines():
    # Using Paranal night sky as an 'arc'
    sky_file = pkg_resources.resource_filename('pypeit', 'data/sky_spec/paranal_sky.fits')
    arx_sky = xspectrum1d.XSpectrum1D.from_file(sky_file)
    arx_amp_true, arx_amp, arx_cent, arx_wid, arx_centerr, arx_w, arx_yprep, _ \
            = arc.detect_lines(arx_sky.flux.value)
    assert (len(arx_w[0]) > 3275)
コード例 #5
0
ファイル: wvutils.py プロジェクト: legolason/PypeIt
def xcorr_shift(inspec1,inspec2, smooth=1.0, percent_ceil=80.0, use_raw_arc=False, sigdetect=10.0, fwhm=4.0, debug=False):

    """ Determine the shift inspec2 relative to inspec1.  This routine computes the shift by finding the maximum of the
    the cross-correlation coefficient. The convention for the shift is that positive shift means inspec2 is shifted to the right
    (higher pixel values) relative to inspec1.

    Args:
        inspec1 : ndarray
            Reference spectrum
        inspec2 : ndarray
            Spectrum for which the shift and stretch are computed such
            that it will match inspec1
        smooth: float, default=1.0
            Gaussian smoothing in pixels applied to both spectra for the
            computations. Default is 5.0
        percent_ceil: float, default=90.0
            Apply a ceiling to the input spectra at the percent_ceil
            percentile level of the distribution of peak amplitudes.
            This prevents extremely strong lines from completely
            dominating the cross-correlation, which can causes the
            cross-correlation to have spurious noise spikes that are not
            the real maximum.
        use_raw_arc: bool, default = False
            If this parameter is True the raw arc will be used rather
            than the continuum subtracted arc
        debug: boolean, default = False

    Returns:
       tuple: Returns the following:

            - shift: float; the shift which was determined
            - cross_corr: float; the maximum of the cross-correlation
              coefficient at this shift

    """

    y1 = smooth_ceil_cont(inspec1,smooth,percent_ceil=percent_ceil,use_raw_arc=use_raw_arc, sigdetect = sigdetect, fwhm = fwhm)
    y2 = smooth_ceil_cont(inspec2,smooth,percent_ceil=percent_ceil,use_raw_arc=use_raw_arc, sigdetect = sigdetect, fwhm = fwhm)

    nspec = y1.shape[0]
    lags = np.arange(-nspec + 1, nspec)
    corr = scipy.signal.correlate(y1, y2, mode='full')
    corr_denom = np.sqrt(np.sum(y1*y1)*np.sum(y2*y2))
    corr_norm = corr/corr_denom
    tampl_true, tampl, pix_max, twid, centerr, ww, arc_cont, nsig = arc.detect_lines(corr_norm, sigdetect=3.0,
                                                                                     fit_frac_fwhm=1.5, fwhm=5.0,
                                                                                     cont_frac_fwhm=1.0, cont_samp=30, nfind=1)
    corr_max = np.interp(pix_max, np.arange(lags.shape[0]),corr_norm)
    lag_max  = np.interp(pix_max, np.arange(lags.shape[0]),lags)
    if debug:
        # Interpolate for bad lines since the fitting code often returns nan
        plt.figure(figsize=(14, 6))
        plt.plot(lags, corr_norm, color='black', drawstyle = 'steps-mid', lw=3, label = 'x-corr', linewidth = 1.0)
        plt.plot(lag_max[0], corr_max[0],'g+', markersize =6.0, label = 'peak')
        plt.title('Best shift = {:5.3f}'.format(lag_max[0]) + ',  corr_max = {:5.3f}'.format(corr_max[0]))
        plt.legend()
        plt.show()

    return lag_max[0], corr_max[0]
コード例 #6
0
ファイル: wvutils.py プロジェクト: p-holguin/PypeIt
def arc_lines_from_spec(spec,
                        sigdetect=10.0,
                        fwhm=4.0,
                        fit_frac_fwhm=1.25,
                        cont_frac_fwhm=1.0,
                        max_frac_fwhm=2.0,
                        cont_samp=30,
                        niter_cont=3,
                        nonlinear_counts=1e10,
                        debug=False):
    """
    Simple wrapper to arc.detect_lines.
    See that code for docs

    Args:
        spec:
        sigdetect:
        fwhm:
        fit_frac_fwhm:
        cont_frac_fwhm:
        max_frac_fwhm:
        cont_samp:
        niter_cont:
        nonlinear_counts:
        debug:

    Returns:
        tuple: all_tcent, all_ecent, cut_tcent, icut, arc_cont_sub. See arc.detect_lines

    """

    # Find peaks
    tampl, tampl_cont, tcent, twid, centerr, w, arc_cont_sub, nsig = arc.detect_lines(
        spec,
        sigdetect=sigdetect,
        fwhm=fwhm,
        fit_frac_fwhm=fit_frac_fwhm,
        cont_frac_fwhm=cont_frac_fwhm,
        max_frac_fwhm=max_frac_fwhm,
        cont_samp=cont_samp,
        niter_cont=niter_cont,
        nonlinear_counts=nonlinear_counts,
        debug=debug)
    all_tcent = tcent[w]
    all_tampl = tampl[w]
    all_ecent = centerr[w]
    all_nsig = nsig[w]

    # Old code cut on amplitude
    # Cut on Amplitude
    #cut_amp = all_tampl > min_ampl

    # Cut on significance
    cut_sig = all_nsig > sigdetect
    cut_tcent = all_tcent[cut_sig]
    icut = np.where(cut_sig)[0]

    # Return
    return all_tcent, all_ecent, cut_tcent, icut, arc_cont_sub
コード例 #7
0
def fit_shift_stretch_iter(inspec1, inspec2, smooth = 5.0, shift_mnmx = (-1.0,1.0), stretch_mnmx = (0.8,1.2), debug = True):



    shift_tot = 0.0
    stretch_tot = 1.0
    niter = 5

    stretch_vec = np.linspace(stretch_mnmx[0],stretch_mnmx[1],endpoint=True, num = 100)
    nspec = inspec1.size
    y1 = scipy.ndimage.filters.gaussian_filter(inspec1, smooth)
    y2 = scipy.ndimage.filters.gaussian_filter(inspec2, smooth)
    bounds = [stretch_mnmx]
    guess = np.array([1.0])

    this_y2 = np.copy(y2)
    for iter in range(niter):
        this_shift, corr_val = xcross_shift_nosm(y1,this_y2)
        shift_tot += this_shift
        #y2_trans = shift_and_stretch(y2,shift,1.0)
        corr_vec = np.zeros_like(stretch_vec)
        for ii in np.arange(stretch_vec.shape[0]):
            corr_vec[ii] = -xcorr_shift_stretch([this_shift, stretch_vec[ii]],y1,this_y2)
        output = arc.detect_lines(corr_vec, nfitpix=7, sigdetect=5.0, fwhm=10.0, mask_width = 3.0, cont_samp=30, nfind=1)
        pix_max = output[1][0]
        this_stretch = np.interp(pix_max, np.arange(stretch_vec.shape[0]), stretch_vec)
        stretch_tot *= this_stretch
        corr_max =  -xcorr_shift_stretch([0.0, this_stretch], y1, this_y2)
        this_y2 = shift_and_stretch(this_y2,0.0,this_stretch)
        if debug:
            # Interpolate for bad lines since the fitting code often returns nan
            plt.figure(figsize=(14, 6))
            plt.plot(stretch_vec, corr_vec, color='black', drawstyle='steps-mid', lw=3, label='x-corr', linewidth=1.0)
            plt.plot(this_stretch, corr_max, 'g+', markersize=6.0, label='peak')
            plt.title('Best stretch = {:5.3f}'.format(this_stretch) + ',  corr_max = {:5.3f}'.format(corr_max))
            plt.legend()
            plt.show()
        if debug and (iter == niter-1):
            x1 = np.arange(nspec)
            inspec2_trans = shift_and_stretch(inspec2, 0.0, this_stretch)
            plt.plot(x1, inspec1, 'k-', drawstyle='steps')
            plt.plot(x1, inspec2_trans, 'r-', drawstyle='steps')
            plt.title('Iteration # {:d}'.format(iter) + ': shift_tot = {:5.3f}'.format(shift_tot) +
                      ',  stretch_tot = {:5.3f}'.format(stretch_tot) + ', corr_tot = {:5.3f}'.format(corr_max))
            plt.show()

    corr_tot = -xcorr_shift_stretch([shift_tot, stretch_tot], y1, y2)
    shift_cc, cc_val = xcross_shift_nosm(y1, y2)
    if debug:
        x1 = np.arange(nspec)
        inspec2_trans = shift_and_stretch(inspec2, shift_tot, stretch_tot)
        plt.plot(x1, inspec1, 'k-', drawstyle='steps')
        plt.plot(x1, inspec2_trans, 'g-', drawstyle='steps')
        plt.title('Iteration # {:d}'.format(iter) + ': shift_tot = {:5.3f}'.format(shift_tot) +
                  ',  stretch_tot = {:5.3f}'.format(stretch_tot) + ', corr_tot = {:5.3f}'.format(corr_tot))
        plt.show()

    return True, shift_tot, stretch_tot, corr_tot, shift_cc, cc_val
コード例 #8
0
ファイル: wavemodel.py プロジェクト: catherinemanea/PypeIt
def create_linelist(wavelength, spec, fwhm, sigdetec=2.,
                    cont_samp=10., line_name=None, file_root_name=None,
                    iraf_frmt=False, debug=False):
    """ Create list of lines detected in a spectrum in a PypeIt
    compatible format. The name of the output file is
    file_root_name+'_lines.dat'.

    Parameters
    ----------
    wavelength : np.array
        wavelength
    spec : np.array
        spectrum
    fwhm : float
        fwhm in pixels used for filtering out arc lines that are too
        wide and not considered in fits. Parameter of arc.detect_lines().
    sigdetec : float
        sigma threshold above fluctuations for line detection. Parameter
        of arc.detect_lines(). Default = 2.
    cont_samp : float
        the number of samples across the spectrum used for continuum
        subtraction. Parameter of arc.detect_lines().  Default = 10.
    line_name : str
        name of the lines to listed in the file.
    file_root_name : str
        name of the file where the identified lines will be stored.
        The code automatically add '_lines.dat' at the end of the
        root name.
    iraf_frmt : bool
        if True, the file is written in the IRAF format (i.e. wavelength,
        ion name, amplitude).
    """

    msgs.info("Searching for peaks {} sigma above background".format(sigdetec))
    tampl_true, tampl, tcent, twid, centerr, ww, arcnorm, nsig = arc.detect_lines(spec, sigdetect=sigdetec,
                                                                                  fwhm=fwhm, cont_samp=cont_samp,
                                                                                  debug=debug)

    peaks_good = tcent[ww]
    ampl_good = tampl[ww]
    # convert from pixel location to wavelength
    pixvec = np.arange(spec.size)
    wave_peak = scipy.interpolate.interp1d(pixvec, wavelength, bounds_error=False, fill_value='extrapolate')(peaks_good)
    npeak = len(wave_peak)
    ion = npeak*[str(line_name)]
    NIST = npeak*[1]
    Instr = npeak*[32]
    Source = npeak*['wavemodel.py']

    if iraf_frmt:
        msgs.info("Printing file in IRAF format: {}".format(file_root_name+'_iraf_lines.dat'))
        ion = np.array(ion)
        id_lines_iraf = np.vstack( (np.round(wave_peak,5), ion, np.round(ampl_good,5)) ).T
        np.savetxt(file_root_name+'_iraf_lines.dat', id_lines_iraf, fmt="%15s %6s %15s", delimiter="  ")
    else:
        msgs.info("Printing file: {}".format(file_root_name+'_lines.dat'))
        dat = Table([wave_peak, ion, NIST, Instr, ampl_good, Source], names=('wave', 'ion','NIST','Instr','amplitude','Source'))
        dat.write(file_root_name+'_lines.dat',format='ascii.fixed_width')
コード例 #9
0
ファイル: wvutils.py プロジェクト: thespacedoctor/PypeIt
def arc_lines_from_spec(spec,
                        sigdetect=10.0,
                        fwhm=4.0,
                        fit_frac_fwhm=1.25,
                        cont_frac_fwhm=1.0,
                        max_frac_fwhm=2.0,
                        cont_samp=30,
                        niter_cont=3,
                        nonlinear_counts=1e10,
                        debug=False):
    """
    Parameters
    ----------
    spec
    siglev
    min_ampl

    Returns
    -------

    """

    # Find peaks
    tampl, tampl_cont, tcent, twid, centerr, w, arc_cont_sub, nsig = arc.detect_lines(
        spec,
        sigdetect=sigdetect,
        fwhm=fwhm,
        fit_frac_fwhm=fit_frac_fwhm,
        cont_frac_fwhm=cont_frac_fwhm,
        max_frac_fwhm=max_frac_fwhm,
        cont_samp=cont_samp,
        niter_cont=niter_cont,
        nonlinear_counts=nonlinear_counts,
        debug=debug)
    all_tcent = tcent[w]
    all_tampl = tampl[w]
    all_ecent = centerr[w]
    all_nsig = nsig[w]

    # Old code cut on amplitude
    # Cut on Amplitude
    #cut_amp = all_tampl > min_ampl

    # Cut on significance
    cut_sig = all_nsig > sigdetect
    cut_tcent = all_tcent[cut_sig]
    icut = np.where(cut_sig)[0]

    # Return
    return all_tcent, all_ecent, cut_tcent, icut, arc_cont_sub
コード例 #10
0
def xcorr_shift(inspec1, inspec2, smooth=None, debug=False):

    if smooth is not None:
        y1 = scipy.ndimage.filters.gaussian_filter(inspec1, smooth)
        y2 = scipy.ndimage.filters.gaussian_filter(inspec2, smooth)
    else:
        y1 = inspec1
        y2 = inspec2

    nspec = y1.shape[0]
    lags = np.arange(-nspec + 1, nspec)
    corr = scipy.signal.correlate(y1, y2, mode='full')
    corr_denom = np.sqrt(np.sum(y1 * y1) * np.sum(y2 * y2))
    corr_norm = corr / corr_denom
    output = arc.detect_lines(corr_norm,
                              nfitpix=7,
                              sigdetect=5.0,
                              fwhm=20.0,
                              mask_width=10.0,
                              cont_samp=30,
                              nfind=1)
    pix_max = output[1]
    corr_max = np.interp(pix_max, np.arange(lags.shape[0]), corr_norm)
    lag_max = np.interp(pix_max, np.arange(lags.shape[0]), lags)
    if debug:
        # Interpolate for bad lines since the fitting code often returns nan
        plt.figure(figsize=(14, 6))
        plt.plot(lags,
                 corr_norm,
                 color='black',
                 drawstyle='steps-mid',
                 lw=3,
                 label='x-corr',
                 linewidth=1.0)
        plt.plot(lag_max[0], corr_max[0], 'g+', markersize=6.0, label='peak')
        plt.title('Best shift = {:5.3f}'.format(lag_max[0]) +
                  ',  corr_max = {:5.3f}'.format(corr_max[0]))
        plt.legend()
        plt.show()

    return lag_max[0], corr_max[0]
コード例 #11
0
def test_detect_lines():
    # Using Paranal night sky as an 'arc'
    arx_sky = data.load_sky_spectrum('paranal_sky.fits')
    arx_amp_true, arx_amp, arx_cent, arx_wid, arx_centerr, arx_w, arx_yprep, _ \
            = arc.detect_lines(arx_sky.flux.value)
    assert (len(arx_w[0]) > 3275)
コード例 #12
0
ファイル: flexure.py プロジェクト: mcoughlin/PypeIt
def spec_flex_shift(obj_skyspec, arx_skyspec, arx_lines, mxshft=20):
    """ Calculate shift between object sky spectrum and archive sky spectrum

    Args:
        obj_skyspec (:class:`linetools.spectra.xspectrum1d.XSpectrum1d`):
            Spectrum of the sky related to our object
        arx_skyspec (:class:`linetools.spectra.xspectrum1d.XSpectrum1d`):
            Archived sky spectrum
        arx_lines (tuple): Line information returned by arc.detect_lines for
            the Archived sky spectrum
        mxshft (float, optional):
            Maximum allowed shift from flexure;  note there are cases that
            have been known to exceed even 30 pixels..

    Returns:
        dict: Contains flexure info
    """

    # TODO None of these routines should have dependencies on XSpectrum1d!

    # Determine the brightest emission lines
    msgs.warn("If we use Paranal, cut down on wavelength early on")
    arx_amp, arx_amp_cont, arx_cent, arx_wid, _, arx_w, arx_yprep, nsig \
            = arx_lines
    obj_amp, obj_amp_cont, obj_cent, obj_wid, _, obj_w, obj_yprep, nsig_obj \
            = arc.detect_lines(obj_skyspec.flux.value)

    # Keep only 5 brightest amplitude lines (xxx_keep is array of
    # indices within arx_w of the 5 brightest)
    arx_keep = np.argsort(arx_amp[arx_w])[-5:]
    obj_keep = np.argsort(obj_amp[obj_w])[-5:]

    # Calculate wavelength (Angstrom per pixel)
    arx_disp = np.append(
        arx_skyspec.wavelength.value[1] - arx_skyspec.wavelength.value[0],
        arx_skyspec.wavelength.value[1:] - arx_skyspec.wavelength.value[:-1])
    obj_disp = np.append(
        obj_skyspec.wavelength.value[1] - obj_skyspec.wavelength.value[0],
        obj_skyspec.wavelength.value[1:] - obj_skyspec.wavelength.value[:-1])

    # Calculate resolution (lambda/delta lambda_FWHM)..maybe don't need
    # this? can just use sigmas
    arx_idx = (arx_cent + 0.5).astype(
        np.int)[arx_w][arx_keep]  # The +0.5 is for rounding
    arx_res = arx_skyspec.wavelength.value[arx_idx]/\
              (arx_disp[arx_idx]*(2*np.sqrt(2*np.log(2)))*arx_wid[arx_w][arx_keep])
    obj_idx = (obj_cent + 0.5).astype(
        np.int)[obj_w][obj_keep]  # The +0.5 is for rounding
    obj_res = obj_skyspec.wavelength.value[obj_idx]/ \
              (obj_disp[obj_idx]*(2*np.sqrt(2*np.log(2)))*obj_wid[obj_w][obj_keep])

    if not np.all(np.isfinite(obj_res)):
        msgs.warn(
            'Failed to measure the resolution of the object spectrum, likely due to error '
            'in the wavelength image.')
        return None
    msgs.info("Resolution of Archive={0} and Observation={1}".format(
        np.median(arx_res), np.median(obj_res)))

    # Determine sigma of gaussian for smoothing
    arx_sig2 = np.power(arx_disp[arx_idx] * arx_wid[arx_w][arx_keep], 2)
    obj_sig2 = np.power(obj_disp[obj_idx] * obj_wid[obj_w][obj_keep], 2)

    arx_med_sig2 = np.median(arx_sig2)
    obj_med_sig2 = np.median(obj_sig2)

    if obj_med_sig2 >= arx_med_sig2:
        smooth_sig = np.sqrt(obj_med_sig2 - arx_med_sig2)  # Ang
        smooth_sig_pix = smooth_sig / np.median(arx_disp[arx_idx])
        arx_skyspec = arx_skyspec.gauss_smooth(smooth_sig_pix * 2 *
                                               np.sqrt(2 * np.log(2)))
    else:
        msgs.warn("Prefer archival sky spectrum to have higher resolution")
        smooth_sig_pix = 0.
        msgs.warn("New Sky has higher resolution than Archive.  Not smoothing")
        #smooth_sig = np.sqrt(arx_med_sig**2-obj_med_sig**2)

    #Determine region of wavelength overlap
    min_wave = max(np.amin(arx_skyspec.wavelength.value),
                   np.amin(obj_skyspec.wavelength.value))
    max_wave = min(np.amax(arx_skyspec.wavelength.value),
                   np.amax(obj_skyspec.wavelength.value))

    #Smooth higher resolution spectrum by smooth_sig (flux is conserved!)
    #    if np.median(obj_res) >= np.median(arx_res):
    #        msgs.warn("New Sky has higher resolution than Archive.  Not smoothing")
    #obj_sky_newflux = ndimage.gaussian_filter(obj_sky.flux, smooth_sig)
    #    else:
    #tmp = ndimage.gaussian_filter(arx_sky.flux, smooth_sig)
    #        arx_skyspec = arx_skyspec.gauss_smooth(smooth_sig_pix*2*np.sqrt(2*np.log(2)))
    #arx_sky.flux = ndimage.gaussian_filter(arx_sky.flux, smooth_sig)

    # Define wavelengths of overlapping spectra
    keep_idx = np.where((obj_skyspec.wavelength.value >= min_wave)
                        & (obj_skyspec.wavelength.value <= max_wave))[0]
    #keep_wave = [i for i in obj_sky.wavelength.value if i>=min_wave if i<=max_wave]

    #Rebin both spectra onto overlapped wavelength range
    if len(keep_idx) <= 50:
        msgs.warn("Not enough overlap between sky spectra")
        return None

    # rebin onto object ALWAYS
    keep_wave = obj_skyspec.wavelength[keep_idx]
    arx_skyspec = arx_skyspec.rebin(keep_wave)
    obj_skyspec = obj_skyspec.rebin(keep_wave)
    # Trim edges (rebinning is junk there)
    arx_skyspec.data['flux'][0, :2] = 0.
    arx_skyspec.data['flux'][0, -2:] = 0.
    obj_skyspec.data['flux'][0, :2] = 0.
    obj_skyspec.data['flux'][0, -2:] = 0.

    # Set minimum to 0.  For bad rebinning and for pernicious extractions
    obj_skyspec.data['flux'][0, :] = np.maximum(obj_skyspec.data['flux'][0, :],
                                                0.)
    arx_skyspec.data['flux'][0, :] = np.maximum(arx_skyspec.data['flux'][0, :],
                                                0.)

    # Normalize spectra to unit average sky count
    norm = np.sum(obj_skyspec.flux.value) / obj_skyspec.npix
    norm2 = np.sum(arx_skyspec.flux.value) / arx_skyspec.npix
    if norm <= 0:
        msgs.warn("Bad normalization of object in flexure algorithm")
        msgs.warn("Will try the median")
        norm = np.median(obj_skyspec.flux.value)
        if norm <= 0:
            msgs.warn("Improper sky spectrum for flexure.  Is it too faint??")
            return None
    if norm2 <= 0:
        msgs.warn(
            'Bad normalization of archive in flexure. You are probably using wavelengths '
            'well beyond the archive.')
        return None
    obj_skyspec.flux = obj_skyspec.flux / norm
    arx_skyspec.flux = arx_skyspec.flux / norm2

    # Deal with bad pixels
    msgs.work("Need to mask bad pixels")

    # Deal with underlying continuum
    msgs.work("Consider taking median first [5 pixel]")
    everyn = obj_skyspec.npix // 20
    pypeitFit_obj, _ = fitting.iterfit(obj_skyspec.wavelength.value,
                                       obj_skyspec.flux.value,
                                       nord=3,
                                       kwargs_bspline={'everyn': everyn},
                                       kwargs_reject={
                                           'groupbadpix': True,
                                           'maxrej': 1
                                       },
                                       maxiter=15,
                                       upper=3.0,
                                       lower=3.0)
    obj_sky_cont, _ = pypeitFit_obj.value(obj_skyspec.wavelength.value)

    obj_sky_flux = obj_skyspec.flux.value - obj_sky_cont
    pypeitFit_sky, _ = fitting.iterfit(arx_skyspec.wavelength.value,
                                       arx_skyspec.flux.value,
                                       nord=3,
                                       kwargs_bspline={'everyn': everyn},
                                       kwargs_reject={
                                           'groupbadpix': True,
                                           'maxrej': 1
                                       },
                                       maxiter=15,
                                       upper=3.0,
                                       lower=3.0)
    arx_sky_cont, _ = pypeitFit_sky.value(arx_skyspec.wavelength.value)
    arx_sky_flux = arx_skyspec.flux.value - arx_sky_cont

    # Consider sharpness filtering (e.g. LowRedux)
    msgs.work("Consider taking median first [5 pixel]")

    #Cross correlation of spectra
    #corr = np.correlate(arx_skyspec.flux, obj_skyspec.flux, "same")
    corr = np.correlate(arx_sky_flux, obj_sky_flux, "same")

    #Create array around the max of the correlation function for fitting for subpixel max
    # Restrict to pixels within maxshift of zero lag
    lag0 = corr.size // 2
    #mxshft = settings.argflag['reduce']['flexure']['maxshift']
    max_corr = np.argmax(corr[lag0 - mxshft:lag0 + mxshft]) + lag0 - mxshft
    subpix_grid = np.linspace(max_corr - 3., max_corr + 3., 7)

    #Fit a 2-degree polynomial to peak of correlation function. JFH added this if/else to not crash for bad slits
    if np.any(np.isfinite(corr[subpix_grid.astype(np.int)])):
        fit = fitting.PypeItFit(xval=subpix_grid,
                                yval=corr[subpix_grid.astype(np.int)],
                                func='polynomial',
                                order=np.atleast_1d(2))
        fit.fit()
        success = True
        max_fit = -0.5 * fit.fitc[1] / fit.fitc[2]
    else:
        fit = fitting.PypeItFit(xval=subpix_grid,
                                yval=0.0 * subpix_grid,
                                func='polynomial',
                                order=np.atleast_1d(2))
        fit.fit()
        success = False
        max_fit = 0.0
        msgs.warn('Flexure compensation failed for one of your objects')

    #Calculate and apply shift in wavelength
    shift = float(max_fit) - lag0
    msgs.info("Flexure correction of {:g} pixels".format(shift))
    #model = (fit[2]*(subpix_grid**2.))+(fit[1]*subpix_grid)+fit[0]

    return dict(polyfit=fit,
                shift=shift,
                subpix=subpix_grid,
                corr=corr[subpix_grid.astype(np.int)],
                sky_spec=obj_skyspec,
                arx_spec=arx_skyspec,
                corr_cen=corr.size / 2,
                smooth=smooth_sig_pix,
                success=success)
コード例 #13
0
def fit_shift_stretch_iter(inspec1,
                           inspec2,
                           smooth=5.0,
                           shift_mnmx=(-1.0, 1.0),
                           stretch_mnmx=(0.8, 1.2),
                           debug=True):

    shift_tot = 0.0
    stretch_tot = 1.0
    niter = 5

    stretch_vec = np.linspace(stretch_mnmx[0],
                              stretch_mnmx[1],
                              endpoint=True,
                              num=100)
    nspec = inspec1.size
    y1 = scipy.ndimage.filters.gaussian_filter(inspec1, smooth)
    y2 = scipy.ndimage.filters.gaussian_filter(inspec2, smooth)
    bounds = [stretch_mnmx]
    guess = np.array([1.0])

    this_y2 = np.copy(y2)
    for iter in range(niter):
        this_shift, corr_val = xcross_shift_nosm(y1, this_y2)
        shift_tot += this_shift
        #y2_trans = shift_and_stretch(y2,shift,1.0)
        corr_vec = np.zeros_like(stretch_vec)
        for ii in np.arange(stretch_vec.shape[0]):
            corr_vec[ii] = -xcorr_shift_stretch([this_shift, stretch_vec[ii]],
                                                y1, this_y2)
        output = arc.detect_lines(corr_vec,
                                  nfitpix=7,
                                  sigdetect=5.0,
                                  fwhm=10.0,
                                  mask_width=3.0,
                                  cont_samp=30,
                                  nfind=1)
        pix_max = output[1][0]
        this_stretch = np.interp(pix_max, np.arange(stretch_vec.shape[0]),
                                 stretch_vec)
        stretch_tot *= this_stretch
        corr_max = -xcorr_shift_stretch([0.0, this_stretch], y1, this_y2)
        this_y2 = shift_and_stretch(this_y2, 0.0, this_stretch)
        if debug:
            # Interpolate for bad lines since the fitting code often returns nan
            plt.figure(figsize=(14, 6))
            plt.plot(stretch_vec,
                     corr_vec,
                     color='black',
                     drawstyle='steps-mid',
                     lw=3,
                     label='x-corr',
                     linewidth=1.0)
            plt.plot(this_stretch,
                     corr_max,
                     'g+',
                     markersize=6.0,
                     label='peak')
            plt.title('Best stretch = {:5.3f}'.format(this_stretch) +
                      ',  corr_max = {:5.3f}'.format(corr_max))
            plt.legend()
            plt.show()
        if debug and (iter == niter - 1):
            x1 = np.arange(nspec)
            inspec2_trans = shift_and_stretch(inspec2, 0.0, this_stretch)
            plt.plot(x1, inspec1, 'k-', drawstyle='steps')
            plt.plot(x1, inspec2_trans, 'r-', drawstyle='steps')
            plt.title('Iteration # {:d}'.format(iter) +
                      ': shift_tot = {:5.3f}'.format(shift_tot) +
                      ',  stretch_tot = {:5.3f}'.format(stretch_tot) +
                      ', corr_tot = {:5.3f}'.format(corr_max))
            plt.show()

    corr_tot = -xcorr_shift_stretch([shift_tot, stretch_tot], y1, y2)
    shift_cc, cc_val = xcross_shift_nosm(y1, y2)
    if debug:
        x1 = np.arange(nspec)
        inspec2_trans = shift_and_stretch(inspec2, shift_tot, stretch_tot)
        plt.plot(x1, inspec1, 'k-', drawstyle='steps')
        plt.plot(x1, inspec2_trans, 'g-', drawstyle='steps')
        plt.title('Iteration # {:d}'.format(iter) +
                  ': shift_tot = {:5.3f}'.format(shift_tot) +
                  ',  stretch_tot = {:5.3f}'.format(stretch_tot) +
                  ', corr_tot = {:5.3f}'.format(corr_tot))
        plt.show()

    return True, shift_tot, stretch_tot, corr_tot, shift_cc, cc_val
コード例 #14
0
ファイル: tracewave.py プロジェクト: thespacedoctor/PypeIt
def tilts_find_lines(arc_spec, slit_cen, tracethresh=10.0, sig_neigh=5.0, nfwhm_neigh=3.0,
                    only_these_lines=None, fwhm=4.0, nonlinear_counts=1e10, fit_frac_fwhm=1.25, cont_frac_fwhm=1.0,
                    max_frac_fwhm=2.0, cont_samp=30, niter_cont=3, debug_lines=False, debug_peaks=False):
    """
    I can't believe this method has no docs

    Args:
        arc_spec:
        slit_cen:
        tracethresh:
        sig_neigh:
        nfwhm_neigh:
        only_these_lines:
        fwhm:
        nonlinear_counts:
        fit_frac_fwhm:
        cont_frac_fwhm:
        max_frac_fwhm:
        cont_samp:
        niter_cont:
        debug_lines:
        debug_peaks:

    Returns:
        (np.ndarray, np.ndarray) or (None,None):

    """


    nspec = arc_spec.size
    spec_vec = np.arange(nspec)
    # Find peaks with a liberal threshold of sigdetect = 5.0
    tampl_tot, tampl_cont_tot, tcent_tot, twid_tot, _, wgood, arc_cont_sub, nsig_tot = arc.detect_lines(
        arc_spec, sigdetect=np.min([sig_neigh,tracethresh]), fwhm=fwhm, fit_frac_fwhm=fit_frac_fwhm, cont_frac_fwhm=cont_frac_fwhm,
        max_frac_fwhm=max_frac_fwhm, cont_samp=cont_samp, niter_cont=niter_cont, nonlinear_counts=nonlinear_counts,
        debug=debug_peaks)
    # Good lines
    arcdet = tcent_tot[wgood]
    arc_ampl = tampl_cont_tot[wgood]
    nsig = nsig_tot[wgood]

    npix_neigh = nfwhm_neigh*fwhm
    # Determine the best lines to use to trace the tilts
    aduse = np.zeros(arcdet.size, dtype=np.bool)  # Which lines should be used to trace the tilts
    w = np.where(nsig >= tracethresh)
    aduse[w] = 1
    # Remove lines that are within npix_neigh pixels.
    # #ToDO replce this with a near-neighbor based approach, where
    # we identify groups and take the brightest line in a given group?
    nuse = np.sum(aduse)
    detuse = arcdet[aduse]
    idxuse = np.arange(arcdet.size)[aduse]
    olduse = aduse.copy()
    for s in range(nuse):
        w = np.where((np.abs(arcdet - detuse[s]) <= npix_neigh) & (np.abs(arcdet - detuse[s]) >= 1.0) & (nsig > sig_neigh))[0]
        for u in range(w.size):
            if nsig[w[u]] > nsig[olduse][s]:
                aduse[idxuse[s]] = False
                break
    # Restricted to ID lines? [introduced to avoid LRIS ghosts]
    if only_these_lines is not None:
        ids_pix = np.array(only_these_lines)
        idxuse = np.arange(arcdet.size)[aduse]
        for s in idxuse:
            if np.min(np.abs(arcdet[s] - ids_pix)) > 2.0:
                msgs.info("Ignoring line at spectral position={:6.1f} which was not identified".format(arcdet[s]))
                aduse[s] = False

    # Final spectral positions of arc lines we will trace
    lines_spec = arcdet[aduse]
    nlines = len(lines_spec)
    if nlines == 0:
        msgs.warn('No arc lines were deemed usable on this slit. Cannot compute tilts. Try lowering tracethresh.')
        msgs.warn('Or, more likely, this was a bad slit (which you might remove)')
        return None, None
    else:
        msgs.info('Modelling arc line tilts with {:d} arc lines'.format(nlines))


    if debug_lines:
        xrng = np.arange(nspec)
        plt.figure(figsize=(14, 6))
        plt.plot(xrng, arc_cont_sub, color='black', drawstyle='steps-mid', lw=3, label='arc', linewidth=1.0)
        plt.plot(arcdet[~aduse], arc_ampl[~aduse], 'r+', markersize=6.0, label='bad for tilts')
        plt.plot(arcdet[aduse], arc_ampl[aduse], 'g+', markersize=6.0, label='good for tilts')
        if nonlinear_counts < 1e9:
            plt.hlines(nonlinear_counts, xrng.min(), xrng.max(), color='orange', linestyle='--', linewidth=2.0,
            label='nonlinear', zorder=10)
        plt.title('Good Lines = {:d}'.format(np.sum(aduse)) + ',  Bad Lines = {:d}'.format(np.sum(~aduse)))
        plt.ylim(arc_cont_sub.min(), 1.5 * arc_cont_sub.max())
        plt.legend()
        plt.show()

    # Spatial position of line, i.e. the central trace interpolated onto the spectral pixel of the line
    lines_spat = np.interp(lines_spec, spec_vec, slit_cen)

    return lines_spec, lines_spat
コード例 #15
0
ファイル: flexure.py プロジェクト: mcoughlin/PypeIt
def spat_flexure_shift(sciimg, slits, debug=False, maxlag=20):
    """
    Calculate a rigid flexure shift in the spatial dimension
    between the slitmask and the science image.

    It is *important* to use original=True when defining the
    slitmask as everything should be relative to the initial slits

    Otherwise, the WaveTilts could get out of sync with science images

    Args:
        sciimg (`numpy.ndarray`_):
        slits (:class:`pypeit.slittrace.SlitTraceSet`):
        maxlag (:obj:`int`, optional):
            Maximum flexure searched for

    Returns:
        float:  The spatial flexure shift relative to the initial slits

    """
    # Mask -- Includes short slits and those excluded by the user (e.g. ['rdx']['slitspatnum'])
    slitmask = slits.slit_img(initial=True,
                              exclude_flag=slits.bitmask.exclude_for_flexure)

    _sciimg = sciimg if slitmask.shape == sciimg.shape \
                else arc.resize_mask2arc(slitmask.shape, sciimg)
    onslits = slitmask > -1
    corr_slits = onslits.astype(float).flatten()

    # Compute
    mean_sci, med_sci, stddev_sci = stats.sigma_clipped_stats(_sciimg[onslits])
    thresh = med_sci + 5.0 * stddev_sci
    corr_sci = np.fmin(_sciimg.flatten(), thresh)

    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
    # TODO -- Generate a QA plot
    tampl_true, tampl, pix_max, twid, centerr, ww, arc_cont, nsig \
            = arc.detect_lines(xcorr_norm, sigdetect=3.0, fit_frac_fwhm=1.5, fwhm=5.0,
                               cont_frac_fwhm=1.0, cont_samp=30, nfind=1, debug=debug)
    # No peak? -- e.g. data fills the entire detector
    if len(tampl) == 0:
        msgs.warn(
            'No peak found in spatial flexure.  Assuming there is none..')
        if debug:
            embed(header='68 of flexure')
        return 0.

    # Find the peak
    xcorr_max = np.interp(pix_max, np.arange(lags.shape[0]), xcorr_norm)
    lag_max = np.interp(pix_max, np.arange(lags.shape[0]), lags)
    msgs.info('Spatial flexure measured: {}'.format(lag_max[0]))

    if debug:
        plt.figure(figsize=(14, 6))
        plt.plot(lags,
                 xcorr_norm,
                 color='black',
                 drawstyle='steps-mid',
                 lw=3,
                 label='x-corr',
                 linewidth=1.0)
        plt.plot(lag_max[0], xcorr_max[0], 'g+', markersize=6.0, label='peak')
        plt.title('Best shift = {:5.3f}'.format(lag_max[0]) +
                  ',  corr_max = {:5.3f}'.format(xcorr_max[0]))
        plt.legend()
        plt.show()

    #tslits_shift = trace_slits.shift_slits(tslits_dict, lag_max)
    # Now translate the tilts

    #slitmask_shift = pixels.tslits2mask(tslits_shift)
    #slitmask_shift = slits.slit_img(flexure=lag_max[0])
    if debug:
        # Now translate the slits in the tslits_dict
        all_left_flexure, all_right_flexure, mask = slits.select_edges(
            flexure=lag_max[0])
        gpm = mask == 0
        viewer, ch = display.show_image(_sciimg)
        #display.show_slits(viewer, ch, left_flexure[:,gpm], right_flexure)[:,gpm]#, slits.id) #, args.det)
        embed(header='83 of flexure.py')

    return lag_max[0]
コード例 #16
0
import scipy

#infile  = 'XSHOOTER_modelsky.fits'
#outfile = 'OH_XSHOOTER_lines.dat'

infile = 'GNIRS_modelsky.fits'
outfile = 'OH_GNIRS_lines.dat'

hdu = fits.open(infile)
spec = hdu[0].data
wave = 1e4 * hdu[1].data
pixvec = np.arange(spec.size)

tampl, tcent, twid, centerr, w, yprep, nsig = arc.detect_lines(spec,
                                                               nfitpix=7,
                                                               sigdetect=2.0,
                                                               FWHM=12,
                                                               cont_samp=10,
                                                               debug=True)
peaks_good = tcent[w]
ampl_good = tampl[w]
wave_peak = scipy.interpolate.interp1d(pixvec,
                                       wave,
                                       bounds_error=False,
                                       fill_value='extrapolate')(peaks_good)
npeak = len(wave_peak)
ion = npeak * ['OH']
NIST = npeak * [1]
Instr = npeak * [32]
Source = npeak * ['IDL code']

dat = Table([wave_peak, ion, NIST, Instr, ampl_good, Source],
コード例 #17
0
ファイル: flexure.py プロジェクト: mcoughlin/PypeIt
def spec_flexure_slit(slits,
                      slitord,
                      slit_bpm,
                      sky_file,
                      method="boxcar",
                      specobjs=None,
                      slit_specs=None,
                      mxshft=None):
    """Calculate the spectral flexure for every slit (global) or object (local)

    Args:
        slits (:class:`~pypeit.slittrace.SlitTraceSet`):
            Slit trace set
        slitord (`numpy.ndarray`_):
            Array of slit/order numbers
        slit_bpm (`numpy.ndarray`_):
            True = masked slit
        sky_file (str):
            Sky file
        method (:obj:`str`, optional):
            Two methods are available:
                - 'boxcar': Recommended for object extractions. This
                  method uses the boxcar extracted sky and wavelength
                  spectra from the input specobjs
                - 'slitcen': Recommended when no objects are being
                  extracted. This method uses a spectrum (stored in
                  slitspecs) that is extracted from the center of
                  each slit.
        specobjs (:class:`~pypeit.specobjs.Specobjs`, optional):
            Spectral extractions
        slit_specs (list, optional):
            A list of linetools.xspectrum1d, one for each slit. The spectra stored in
            this list are sky spectra, extracted from the center of each slit.
        mxshft (int, optional):
            Passed to flex_shift()

    Returns:
        :obj:`list`: A list of :obj:`dict` objects containing flexure
        results of each slit. This is filled with a basically empty
        dict if the slit is skipped.
    """
    sv_fdict = None
    msgs.work("Consider doing 2 passes in flexure as in LowRedux")

    # Determine the method
    slit_cen = True if (specobjs is None) or (method == "slitcen") else False

    # Load Archive. Save the line information to avoid the performance hit from calling it on the archive sky spectrum
    # multiple times
    sky_spectrum = load_sky_spectrum(sky_file)
    sky_lines = arc.detect_lines(sky_spectrum.flux.value)

    nslits = slits.nslits
    gpm = np.logical_not(slit_bpm)
    gdslits = np.where(gpm)[0]

    # Initialise the flexure list for each slit
    flex_list = []
    # Slit/objects to come back to
    return_later_sobjs = []

    # Loop over slits, and then over objects
    for islit in range(nslits):
        msgs.info("Working on spectral flexure of slit: {:d}".format(islit))

        # Reset
        flex_dict = dict(polyfit=[],
                         shift=[],
                         subpix=[],
                         corr=[],
                         corr_cen=[],
                         spec_file=sky_file,
                         smooth=[],
                         arx_spec=[],
                         sky_spec=[],
                         method=[])

        # If no objects on this slit append an empty dictionary
        if islit not in gdslits:
            flex_list.append(flex_dict.copy())
            continue

        if slit_cen:
            sky_wave = slit_specs[islit].wavelength.value
            sky_flux = slit_specs[islit].flux.value

            # Calculate the shift
            fdict = spec_flex_shift(slit_specs[islit],
                                    sky_spectrum,
                                    sky_lines,
                                    mxshft=mxshft)
            # Failed?
            if fdict is not None:
                # Update dict
                for key in [
                        'polyfit', 'shift', 'subpix', 'corr', 'corr_cen',
                        'smooth', 'arx_spec'
                ]:
                    flex_dict[key].append(fdict[key])
                # Interpolate
                sky_wave_new = flexure_interp(fdict['shift'], sky_wave)
                flex_dict['sky_spec'].append(
                    xspectrum1d.XSpectrum1D.from_tuple(
                        (sky_wave_new, sky_flux)))
                flex_dict['method'].append("slitcen")
        else:
            i_slitord = slitord[islit]
            indx = specobjs.slitorder_indices(i_slitord)
            this_specobjs = specobjs[indx]
            # Loop through objects
            for ss, sobj in enumerate(this_specobjs):
                if sobj is None:
                    continue
                if sobj['BOX_WAVE'] is None:  #len(specobj._data.keys()) == 1:  # Nothing extracted; only the trace exists
                    continue
                msgs.info(
                    "Working on flexure for object # {:d}".format(sobj.OBJID) +
                    "in slit # {:d}".format(islit))

                # Using boxcar
                sky_wave = sobj.BOX_WAVE
                sky_flux = sobj.BOX_COUNTS_SKY

                # Generate 1D spectrum for object
                obj_sky = xspectrum1d.XSpectrum1D.from_tuple(
                    (sky_wave, sky_flux))

                # Calculate the shift
                fdict = spec_flex_shift(obj_sky,
                                        sky_spectrum,
                                        sky_lines,
                                        mxshft=mxshft)
                punt = False
                if fdict is None:
                    msgs.warn(
                        "Flexure shift calculation failed for this spectrum.")
                    if sv_fdict is not None:
                        msgs.warn(
                            "Will used saved estimate from a previous slit/object"
                        )
                        fdict = copy.deepcopy(sv_fdict)
                    else:
                        # One does not exist yet
                        # Save it for later
                        return_later_sobjs.append([islit, ss])
                        punt = True
                else:
                    sv_fdict = copy.deepcopy(fdict)

                # Punt?
                if punt:
                    break

                # Update dict
                for key in [
                        'polyfit', 'shift', 'subpix', 'corr', 'corr_cen',
                        'smooth', 'arx_spec', 'sky_spec'
                ]:
                    flex_dict[key].append(fdict[key])
                flex_dict['method'].append("boxcar")

        # Check if we need to go back
        # TODO :: This code just throws an error... probably need to delete or fix this "local" spectral flexure code
        if not slit_cen:
            # Do we need to go back?
            for items in return_later_sobjs:
                if sv_fdict is None:
                    msgs.info("No flexure corrections could be made")
                    break
                # Setup
                msgs.error("This probably needs to be updated")
                slit, ss = items
                flex_dict = flex_list[slit]
                sobj = specobjs[ss]
                # Copy me
                fdict = copy.deepcopy(sv_fdict)
                # Update dict
                for key in [
                        'polyfit', 'shift', 'subpix', 'corr', 'corr_cen',
                        'smooth', 'arx_spec', 'sky_spec'
                ]:
                    flex_dict[key].append(fdict[key])
                flex_dict['method'].append("boxcar")

        # Append, this will be an empty dictionary if the flexure failed
        flex_list.append(flex_dict.copy())

    return flex_list
コード例 #18
0
def flex_shift(obj_skyspec, arx_skyspec, mxshft=20):
    """ Calculate shift between object sky spectrum and archive sky spectrum

    Parameters
    ----------
    obj_skyspec
    arx_skyspec

    Returns
    -------
    flex_dict: dict
      Contains flexure info
    """

    # TODO None of these routines should have dependencies on XSpectrum1d!

    # Determine the brightest emission lines
    msgs.warn("If we use Paranal, cut down on wavelength early on")
    arx_amp, arx_amp_cont, arx_cent, arx_wid, _, arx_w, arx_yprep, nsig = arc.detect_lines(
        arx_skyspec.flux.value)
    obj_amp, obj_amp_cont, obj_cent, obj_wid, _, obj_w, obj_yprep, nsig_obj = arc.detect_lines(
        obj_skyspec.flux.value)

    # Keep only 5 brightest amplitude lines (xxx_keep is array of
    # indices within arx_w of the 5 brightest)
    arx_keep = np.argsort(arx_amp[arx_w])[-5:]
    obj_keep = np.argsort(obj_amp[obj_w])[-5:]

    # Calculate wavelength (Angstrom per pixel)
    arx_disp = np.append(
        arx_skyspec.wavelength.value[1] - arx_skyspec.wavelength.value[0],
        arx_skyspec.wavelength.value[1:] - arx_skyspec.wavelength.value[:-1])
    #arx_disp = (np.amax(arx_sky.wavelength.value)-np.amin(arx_sky.wavelength.value))/arx_sky.wavelength.size
    obj_disp = np.append(
        obj_skyspec.wavelength.value[1] - obj_skyspec.wavelength.value[0],
        obj_skyspec.wavelength.value[1:] - obj_skyspec.wavelength.value[:-1])
    #obj_disp = (np.amax(obj_sky.wavelength.value)-np.amin(obj_sky.wavelength.value))/obj_sky.wavelength.size

    # Calculate resolution (lambda/delta lambda_FWHM)..maybe don't need
    # this? can just use sigmas
    arx_idx = (arx_cent + 0.5).astype(
        np.int)[arx_w][arx_keep]  # The +0.5 is for rounding
    arx_res = arx_skyspec.wavelength.value[arx_idx]/\
              (arx_disp[arx_idx]*(2*np.sqrt(2*np.log(2)))*arx_wid[arx_w][arx_keep])
    obj_idx = (obj_cent + 0.5).astype(
        np.int)[obj_w][obj_keep]  # The +0.5 is for rounding
    obj_res = obj_skyspec.wavelength.value[obj_idx]/ \
              (obj_disp[obj_idx]*(2*np.sqrt(2*np.log(2)))*obj_wid[obj_w][obj_keep])
    #obj_res = (obj_sky.wavelength.value[0]+(obj_disp*obj_cent[obj_w][obj_keep]))/(
    #    obj_disp*(2*np.sqrt(2*np.log(2)))*obj_wid[obj_w][obj_keep])

    if not np.all(np.isfinite(obj_res)):
        msgs.warn(
            'Failed to measure the resolution of the object spectrum, likely due to error '
            'in the wavelength image.')
        return None
    msgs.info("Resolution of Archive={0} and Observation={1}".format(
        np.median(arx_res), np.median(obj_res)))

    # Determine sigma of gaussian for smoothing
    arx_sig2 = np.power(arx_disp[arx_idx] * arx_wid[arx_w][arx_keep], 2)
    obj_sig2 = np.power(obj_disp[obj_idx] * obj_wid[obj_w][obj_keep], 2)

    arx_med_sig2 = np.median(arx_sig2)
    obj_med_sig2 = np.median(obj_sig2)

    if obj_med_sig2 >= arx_med_sig2:
        smooth_sig = np.sqrt(obj_med_sig2 - arx_med_sig2)  # Ang
        smooth_sig_pix = smooth_sig / np.median(arx_disp[arx_idx])
        arx_skyspec = arx_skyspec.gauss_smooth(smooth_sig_pix * 2 *
                                               np.sqrt(2 * np.log(2)))
    else:
        msgs.warn("Prefer archival sky spectrum to have higher resolution")
        smooth_sig_pix = 0.
        msgs.warn("New Sky has higher resolution than Archive.  Not smoothing")
        #smooth_sig = np.sqrt(arx_med_sig**2-obj_med_sig**2)

    #Determine region of wavelength overlap
    min_wave = max(np.amin(arx_skyspec.wavelength.value),
                   np.amin(obj_skyspec.wavelength.value))
    max_wave = min(np.amax(arx_skyspec.wavelength.value),
                   np.amax(obj_skyspec.wavelength.value))

    #Smooth higher resolution spectrum by smooth_sig (flux is conserved!)
    #    if np.median(obj_res) >= np.median(arx_res):
    #        msgs.warn("New Sky has higher resolution than Archive.  Not smoothing")
    #obj_sky_newflux = ndimage.gaussian_filter(obj_sky.flux, smooth_sig)
    #    else:
    #tmp = ndimage.gaussian_filter(arx_sky.flux, smooth_sig)
    #        arx_skyspec = arx_skyspec.gauss_smooth(smooth_sig_pix*2*np.sqrt(2*np.log(2)))
    #arx_sky.flux = ndimage.gaussian_filter(arx_sky.flux, smooth_sig)

    # Define wavelengths of overlapping spectra
    keep_idx = np.where((obj_skyspec.wavelength.value >= min_wave)
                        & (obj_skyspec.wavelength.value <= max_wave))[0]
    #keep_wave = [i for i in obj_sky.wavelength.value if i>=min_wave if i<=max_wave]

    #Rebin both spectra onto overlapped wavelength range
    if len(keep_idx) <= 50:
        msgs.warn("Not enough overlap between sky spectra")
        return None
    else:  #rebin onto object ALWAYS
        keep_wave = obj_skyspec.wavelength[keep_idx]
        arx_skyspec = arx_skyspec.rebin(keep_wave)
        obj_skyspec = obj_skyspec.rebin(keep_wave)
        # Trim edges (rebinning is junk there)
        arx_skyspec.data['flux'][0, :2] = 0.
        arx_skyspec.data['flux'][0, -2:] = 0.
        obj_skyspec.data['flux'][0, :2] = 0.
        obj_skyspec.data['flux'][0, -2:] = 0.

    # Normalize spectra to unit average sky count
    norm = np.sum(obj_skyspec.flux.value) / obj_skyspec.npix
    obj_skyspec.flux = obj_skyspec.flux / norm
    norm2 = np.sum(arx_skyspec.flux.value) / arx_skyspec.npix
    arx_skyspec.flux = arx_skyspec.flux / norm2
    if (norm < 0.):
        msgs.warn("Bad normalization of object in flexure algorithm")
        msgs.warn("Will try the median")
        norm = np.median(obj_skyspec.flux.value)
        if (norm < 0.):
            msgs.warn("Improper sky spectrum for flexure.  Is it too faint??")
            return None
    if (norm2 < 0.):
        msgs.warn(
            'Bad normalization of archive in flexure. You are probably using wavelengths '
            'well beyond the archive.')
        return None

    # Deal with bad pixels
    msgs.work("Need to mask bad pixels")

    # Deal with underlying continuum
    msgs.work("Consider taking median first [5 pixel]")
    everyn = obj_skyspec.npix // 20
    bspline_par = dict(everyn=everyn)
    mask, ct = utils.robust_polyfit(obj_skyspec.wavelength.value,
                                    obj_skyspec.flux.value,
                                    3,
                                    function='bspline',
                                    sigma=3.,
                                    bspline_par=bspline_par)
    obj_sky_cont = utils.func_val(ct, obj_skyspec.wavelength.value, 'bspline')
    obj_sky_flux = obj_skyspec.flux.value - obj_sky_cont
    mask, ct_arx = utils.robust_polyfit(arx_skyspec.wavelength.value,
                                        arx_skyspec.flux.value,
                                        3,
                                        function='bspline',
                                        sigma=3.,
                                        bspline_par=bspline_par)
    arx_sky_cont = utils.func_val(ct_arx, arx_skyspec.wavelength.value,
                                  'bspline')
    arx_sky_flux = arx_skyspec.flux.value - arx_sky_cont

    # Consider sharpness filtering (e.g. LowRedux)
    msgs.work("Consider taking median first [5 pixel]")

    #Cross correlation of spectra
    #corr = np.correlate(arx_skyspec.flux, obj_skyspec.flux, "same")
    corr = np.correlate(arx_sky_flux, obj_sky_flux, "same")

    #Create array around the max of the correlation function for fitting for subpixel max
    # Restrict to pixels within maxshift of zero lag
    lag0 = corr.size // 2
    #mxshft = settings.argflag['reduce']['flexure']['maxshift']
    max_corr = np.argmax(corr[lag0 - mxshft:lag0 + mxshft]) + lag0 - mxshft
    subpix_grid = np.linspace(max_corr - 3., max_corr + 3., 7)

    #Fit a 2-degree polynomial to peak of correlation function. JFH added this if/else to not crash for bad slits
    if np.any(np.isfinite(corr[subpix_grid.astype(np.int)])):
        fit = utils.func_fit(subpix_grid, corr[subpix_grid.astype(np.int)],
                             'polynomial', 2)
        success = True
        max_fit = -0.5 * fit[1] / fit[2]
    else:
        fit = utils.func_fit(subpix_grid, 0.0 * subpix_grid, 'polynomial', 2)
        success = False
        max_fit = 0.0
        msgs.warn('Flexure compensation failed for one of your objects')

    #Calculate and apply shift in wavelength
    shift = float(max_fit) - lag0
    msgs.info("Flexure correction of {:g} pixels".format(shift))
    #model = (fit[2]*(subpix_grid**2.))+(fit[1]*subpix_grid)+fit[0]

    flex_dict = dict(polyfit=fit,
                     shift=shift,
                     subpix=subpix_grid,
                     corr=corr[subpix_grid.astype(np.int)],
                     sky_spec=obj_skyspec,
                     arx_spec=arx_skyspec,
                     corr_cen=corr.size / 2,
                     smooth=smooth_sig_pix,
                     success=success)
    # Return
    return flex_dict
コード例 #19
0
from astropy.table import Table
from astropy.io import fits
from pypeit.core import arc
import numpy as np
import scipy

#infile  = 'XSHOOTER_modelsky.fits'
#outfile = 'OH_XSHOOTER_lines.dat'

infile  = 'GNIRS_modelsky.fits'
outfile = 'OH_GNIRS_lines.dat'


hdu = fits.open(infile)
spec = hdu[0].data
wave = 1e4*hdu[1].data
pixvec = np.arange(spec.size)

tampl, tcent, twid, centerr, w, yprep, nsig = arc.detect_lines(spec, nfitpix=7, sigdetect = 2.0, FWHM = 12, cont_samp = 10, debug = True)
peaks_good = tcent[w]
ampl_good = tampl[w]
wave_peak = scipy.interpolate.interp1d(pixvec, wave, bounds_error=False, fill_value='extrapolate')(peaks_good)
npeak = len(wave_peak)
ion = npeak*['OH']
NIST = npeak*[1]
Instr = npeak*[32]
Source = npeak*['IDL code']

dat = Table([wave_peak, ion, NIST, Instr, ampl_good, Source], names=('wave', 'ion','NIST','Instr','amplitude','Source'))
dat.write(outfile,format='ascii.fixed_width')