Пример #1
0
def test_legendre():
    x = np.pi*np.linspace(0, 1., 100)
    y = np.sin(x)
    # Legendre
    pypeitFit = fitting.PypeItFit(xval=x, yval=y, func='legendre', order=np.array([3]))
    pypeitFit.fit() # = fitting.func_fit(x, y, 'legendre', 3)
    np.testing.assert_allclose(pypeitFit.fitc, np.array([  6.37115652e-01,   6.83317251e-17,
                                                   -6.84581686e-01, -7.59352737e-17]), atol=1e-9)
Пример #2
0
def test_pypeitfit():
    out_file = data_path('test_fit.fits')
    if os.path.isfile(out_file):
        os.remove(out_file)
    pypeitFit = fitting.PypeItFit(fitc=np.arange(100).astype(float))
    # Write
    pypeitFit.to_file(out_file)
    # Read
    pypeitFit2 = fitting.PypeItFit.from_file(out_file)
    assert np.array_equal(pypeitFit.fitc, pypeitFit2.fitc)
    pypeitFit2.to_file(out_file, overwrite=True)
    # Finish
    os.remove(out_file)
Пример #3
0
def test_polynomial():
    """ Run the parameter setup script
    """
    x = np.pi*np.linspace(0, 1., 100)
    y = np.sin(x)
    # Polynomial
    pypeitFit = fitting.PypeItFit(xval=x, yval=y, func='polynomial', order=np.array([3]))
    pypeitFit.fit()
    #pypeitFit = fitting.func_fit(x, y, 'polynomial', 3)
    np.testing.assert_allclose(pypeitFit.fitc, np.array([ -4.74660344e-02,   1.30745471e+00,
                                                  -4.16175760e-01, 3.08557167e-18]), atol=1e-9)
    # Evaluate
    val = pypeitFit.eval(x)
    assert np.isclose(val[0], -0.04746603), 'Bad value'
Пример #4
0
def pypeit_arcspec(in_file, slit, binspec, binning=None):
    """
    Load up the arc spectrum from an input JSON file

    Args:
        in_file (str):
            File containing the arc spectrum and or fit
        slit (int):
            slit index

    Returns:
        tuple: np.ndarray, np.ndarray, PypeItFit:  wave, flux, pypeitFitting

    """
    if 'json' in in_file:
        wv_dict = ltu.loadjson(in_file)
        iwv_calib = wv_dict[str(slit)]
        pypeitFitting = fitting.PypeItFit(fitc=np.array(iwv_calib['fitc']),
                                          func=iwv_calib['function'],
                                          minx=iwv_calib['fmin'],
                                          maxx=iwv_calib['fmax'])

        if binning is not None and binning != binspec:
            embed(header='Not ready for this yet!')
        else:
            x = np.arange(len(iwv_calib['spec']))

        wv_vac = pypeitFitting.eval(x / iwv_calib['xnorm'])
        #wv_vac = utils.func_val(iwv_calib['fitc'], x/iwv_calib['xnorm'], iwv_calib['function'],
        #                   minx=iwv_calib['fmin'], maxx=iwv_calib['fmax'])
        flux = np.array(iwv_calib['spec']).flatten()
    elif 'fits' in in_file:
        wvcalib = wavecalib.WaveCalib.from_file(in_file)
        idx = np.where(wvcalib.spat_ids == slit)[0][0]
        flux = wvcalib.arc_spectra[:, idx]
        #
        npix = flux.size
        if binning is not None and binning != binspec:
            npix = int(npix * binning / binspec)
            x = np.arange(npix) / (npix - 1)
        else:
            x = np.arange(npix) / (npix - 1)
        # Evaluate
        wv_vac = wvcalib.wv_fits[idx].pypeitfit.eval(x)
        pypeitFitting = wvcalib.wv_fits[idx].pypeitfit
    else:
        raise IOError("Bad in_file {}".format(in_file))

    # Return
    return wv_vac, flux, pypeitFitting
Пример #5
0
def test_wavefit():
    "Fuss with the WaveFit DataContainer"
    out_file = data_path('test_wavefit.fits')
    if os.path.isfile(out_file):
        os.remove(out_file)
    pypeitFit = fitting.PypeItFit(fitc=np.arange(5).astype(float))
    #
    ions = np.asarray(['CdI', 'HgI'])
    ion_bits = np.zeros(len(ions),
                        dtype=wv_fitting.WaveFit.bitmask.minimum_dtype())
    for kk, ion in enumerate(ions):
        ion_bits[kk] = wv_fitting.WaveFit.bitmask.turn_on(ion_bits[kk], ion)
    # Do it
    waveFit = wv_fitting.WaveFit(99,
                                 pypeitfit=pypeitFit,
                                 pixel_fit=np.arange(10).astype(float),
                                 wave_fit=np.linspace(1., 10., 10),
                                 sigrej=3.,
                                 ion_bits=ion_bits)

    # Write
    waveFit.to_file(out_file)
    # Read
    waveFit2 = wv_fitting.WaveFit.from_file(out_file)
    assert np.array_equal(waveFit.pypeitfit.fitc, waveFit2.pypeitfit.fitc)
    # Write again
    waveFit2.to_file(out_file, overwrite=True)
    # And one more read
    waveFit2b = wv_fitting.WaveFit.from_file(out_file)
    assert np.array_equal(waveFit.pypeitfit.fitc, waveFit2b.pypeitfit.fitc)
    # Finish
    os.remove(out_file)

    # No fit
    waveFit3 = wv_fitting.WaveFit(99,
                                  pypeitfit=None,
                                  pixel_fit=np.arange(10).astype(float),
                                  wave_fit=np.linspace(1., 10., 10),
                                  sigrej=3.,
                                  ion_bits=ion_bits)
    waveFit3.to_file(out_file)
    waveFit4 = wv_fitting.WaveFit.from_file(out_file)
    assert waveFit4.pypeitfit is None

    # Clean up
    os.remove(out_file)
Пример #6
0
def test_wavecalib():
    "Fuss with the WaveCalib DataContainer"
    out_file = data_path('test_wavecalib.fits')
    if os.path.isfile(out_file):
        os.remove(out_file)
    # Pieces
    pypeitFit = fitting.PypeItFit(fitc=np.arange(5).astype(float),
                                  xval=np.linspace(1, 100., 100))
    # 2D fit
    pypeitFit2 = fitting.PypeItFit(fitc=np.linspace((1, 2), (10, 20), 10),
                                   xval=np.linspace(1, 100., 100),
                                   x2=np.linspace(1, 100., 100))
    waveFit = wv_fitting.WaveFit(232,
                                 pypeitfit=pypeitFit,
                                 pixel_fit=np.arange(10).astype(float),
                                 wave_fit=np.linspace(1., 10., 10))

    waveCalib = wavecalib.WaveCalib(wv_fits=np.asarray([waveFit]),
                                    nslits=1,
                                    spat_ids=np.asarray([232]),
                                    wv_fit2d=pypeitFit2)

    # Write
    waveCalib.to_file(out_file)

    # Read
    waveCalib2 = wavecalib.WaveCalib.from_file(out_file)

    # Test
    assert np.array_equal(waveCalib.spat_ids,
                          waveCalib2.spat_ids), 'Bad spat_ids'
    assert np.array_equal(waveCalib.wv_fits[0].pypeitfit.fitc,
                          waveCalib2.wv_fits[0].pypeitfit.fitc), 'Bad fitc'
    assert np.array_equal(waveCalib.wv_fit2d.xval, waveCalib2.wv_fit2d.xval)

    # Write again!
    waveCalib2.to_file(out_file, overwrite=True)

    # Finish
    os.remove(out_file)

    # With None (failed wave)
    spat_ids = np.asarray([232, 949])
    waveCalib3 = wavecalib.WaveCalib(wv_fits=np.asarray(
        [waveFit, wv_fitting.WaveFit(949)]),
                                     nslits=2,
                                     spat_ids=spat_ids,
                                     wv_fit2d=pypeitFit2)
    waveCalib3.to_file(out_file)
    waveCalib4 = wavecalib.WaveCalib.from_file(out_file)

    # Check masking
    slits = slittrace.SlitTraceSet(left_init=np.full((1000, 2), 2,
                                                     dtype=float),
                                   right_init=np.full((1000, 2),
                                                      8,
                                                      dtype=float),
                                   pypeline='MultiSlit',
                                   spat_id=spat_ids,
                                   nspat=2,
                                   PYP_SPEC='dummy')
    slits.mask_wvcalib(waveCalib3)
    assert slits.bitmask.flagged(slits.mask[1], flag='BADWVCALIB')

    # Finish
    os.remove(out_file)
Пример #7
0
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)