Exemplo n.º 1
0
def get_continuum(flux):
    # Fit continuum
    x = np.arange(len(flux))
    ybin,bin_edges,binnumber = bindata.binned_statistic(x,flux,statistic='median',bins=10)
    xbin = bin_edges[0:-1]+(bin_edges[1]-bin_edges[0])*0.5
    cont = dln.interp(xbin,ybin,x,extrapolate=True)
    return cont
Exemplo n.º 2
0
    def interp(self, x=None, xtype='wave', order=None):
        """ Interpolate onto a new wavelength scale and/or shift by a velocity."""
        # if x is 2D and has multiple dimensions and the spectrum does as well
        # (with the same number of dimensions), and order=None, then it is assumed
        # that the input and output orders are "matched".

        # Check input xtype
        if (xtype.lower().find('wave') == -1) & (xtype.lower().find('pix')
                                                 == -1):
            raise ValueError(xtype + ' not supported.  Must be wave or pixel')

        # Convert pixels to wavelength
        if (xtype.lower().find('pix') > -1):
            wave = self.pix2wave(x, order=order)
        else:
            wave = x.copy()

        # How many orders in output wavelength
        if (wave.ndim == 1):
            nwpix = len(wave)
            nworder = 1
        else:
            nwpix, nworder = wave.shape
        wave = wave.reshape(nwpix, nworder)  # make 2D for order indexing

        # Loop over orders in final wavelength
        oflux = np.zeros((nwpix, nworder), float)
        oerr = np.zeros((nwpix, nworder), float)
        omask = np.zeros((nwpix, nworder), bool)
        osigma = np.zeros((nwpix, nworder), float)
        for i in range(nworder):
            # Interpolate onto the final wavelength scale
            wave1 = wave[:, i]
            wr1 = dln.minmax(wave1)

            # Make spectrum arrays 2D for order indexing, [Npix,Norder]
            swave = self.wave.reshape(self.npix, self.norder)
            sflux = self.flux.reshape(self.npix, self.norder)
            serr = self.err.reshape(self.npix, self.norder)
            # convert mask to integer 0 or 1
            if hasattr(self, 'mask'):
                smask = np.zeros((self.npix, self.norder), int)
                smask_bool = self.err.reshape(self.npix, self.norder)
                smask[smask_bool == True] = 1
            else:
                smask = np.zeros((self.npix, self.norder), int)

            # The orders are "matched", one input for one output order
            if (nworder == self.norder) & (order is None):
                swave1 = swave[:, i]
                sflux1 = sflux[:, i]
                serr1 = serr[:, i]
                ssigma1 = self.lsf.sigma(order=i)
                smask1 = smask[:, i]
                # Some overlap
                if (np.min(swave1) < wr1[1]) & (np.max(swave1) > wr1[0]):
                    # Fix NaN pixels
                    bd, nbd = dln.where(np.isfinite(sflux1) == False)
                    if nbd > 0:
                        sflux1[bd] = 1.0
                        serr1[bd] = 1e30
                        smask1[bd] = 1
                    ind, nind = dln.where((wave1 > np.min(swave1))
                                          & (wave1 < np.max(swave1)))
                    oflux[ind, i] = dln.interp(swave1,
                                               sflux1,
                                               wave1[ind],
                                               extrapolate=False,
                                               assume_sorted=False)
                    oerr[ind, i] = dln.interp(swave1,
                                              serr1,
                                              wave1[ind],
                                              extrapolate=False,
                                              assume_sorted=False,
                                              kind='linear')
                    osigma[ind, i] = dln.interp(swave1,
                                                ssigma1,
                                                wave1[ind],
                                                extrapolate=False,
                                                assume_sorted=False)
                    # Gauss-Hermite, convert to wavelength units
                    if self.lsf.lsftype == 'Gauss-Hermite':
                        sdw1 = np.abs(swave1[1:] - swave1[0:-1])
                        sdw1 = np.hstack((sdw1, sdw1[-1]))
                        dw = dln.interp(swave1,
                                        sdw1,
                                        wave1[ind],
                                        extrapolate=False,
                                        assume_sorted=False)
                        osigma[ind, i] *= dw  # in Ang
                    mask_interp = dln.interp(swave1,
                                             smask1,
                                             wave1[ind],
                                             extrapolate=False,
                                             assume_sorted=False)
                    mask_interp_bool = np.zeros(nind, bool)
                    mask_interp_bool[mask_interp > 0.4] = True
                    omask[ind, i] = mask_interp_bool

            # Loop over all spectrum orders
            else:
                # Loop over spectrum orders
                for j in range(self.norder):
                    swave1 = swave[:, j]
                    sflux1 = sflux[:, j]
                    serr1 = serr[:, j]
                    ssigma1 = self.lsf.sigma(order=j)
                    smask1 = smask[:, j]
                    # Some overlap
                    if (np.min(swave1) < wr1[1]) & (np.max(swave1) > wr1[0]):
                        ind, nind = dln.where((wave1 > np.min(swave1))
                                              & (wave1 < np.max(swave1)))
                        oflux[ind, i] = dln.interp(swave1,
                                                   sflux1,
                                                   wave1[ind],
                                                   extrapolate=False,
                                                   assume_sorted=False)
                        oerr[ind, i] = dln.interp(swave1,
                                                  serr1,
                                                  wave1[ind],
                                                  extrapolate=False,
                                                  assume_sorted=False,
                                                  kind='linear')
                        osigma[ind, i] = dln.interp(swave1,
                                                    ssigma1,
                                                    wave1[ind],
                                                    extrapolate=False,
                                                    assume_sorted=False)
                        mask_interp = dln.interp(swave1,
                                                 smask1,
                                                 wave1[ind],
                                                 extrapolate=False,
                                                 assume_sorted=False)
                        mask_interp_bool = np.zeros(nind, bool)
                        mask_interp_bool[mask_interp > 0.4] = True
                        omask[ind, i] = mask_interp_bool
                    # Currently this does NOT deal with the overlap of multiple orders (e.g. averaging)
        # Flatten if 1D
        if (x.ndim == 1):
            wave = wave.flatten()
            oflux = oflux.flatten()
            oerr = oerr.flatten()
            osigma = osigma.flatten()
            omask = omask.flatten()
        # Create output spectrum object
        if self.lsf.lsftype == 'Gauss-Hermite':
            # Can't interpolate Gauss-Hermite LSF yet
            # instead convert to a Gaussian approximation in wavelength units
            #print('Cannot interpolate Gauss-Hermite LSF yet')
            lsfxtype = 'wave'
        else:
            lsfxtype = self.lsf.xtype
        ospec = Spec1D(oflux,
                       wave=wave,
                       err=oerr,
                       mask=omask,
                       lsftype='Gaussian',
                       lsfxtype=lsfxtype,
                       lsfsigma=osigma)

        return ospec
Exemplo n.º 3
0
def continuum(spec, norder=6, perclevel=90.0, binsize=0.1, interp=True):
    """
    Measure the continuum of a spectrum.

    Parameters
    ----------
    spec : Spec1D object
           A spectrum object.  This at least needs
                to have a FLUX and WAVE attribute.
    norder : float, optional
            Polynomial order to use for the continuum fitting.
            The default is 6.
    perclevel : float, optional
            Percent level to use for the continuum value
            in large bins.  Default is 90.
    binsize : float, optional
            Fraction of the wavelength range (scaled to -1 to +1) to bin.
            Default is 0.1.
    interp : bool, optional
            Use interpolation of the binned values instead of a polynomial
            fit.  Default is True.

    Returns
    -------
    cont : numpy array
            The continuum array, in the same shape as the input flux.

    Examples
    --------
    .. code-block:: python

         cont = continuum(spec)

    """

    wave = spec.wave.copy().reshape(spec.npix, spec.norder)  # make 2D
    flux = spec.flux.copy().reshape(spec.npix, spec.norder)  # make 2D
    err = spec.err.copy().reshape(spec.npix, spec.norder)  # make 2D
    mask = spec.mask.copy().reshape(spec.npix, spec.norder)  # make 2D
    cont = err.copy() * 0.0 + 1
    for o in range(spec.norder):
        w = wave[:, o].copy()
        wr = [np.min(w), np.max(w)]
        x = (w - np.mean(wr)) / dln.valrange(wr) * 2  # -1 to +1
        y = flux[:, o].copy()
        m = mask[:, o].copy()
        # Divide by median
        medy = np.nanmedian(y)
        if medy <= 0.0:
            medy = 1.0
        y /= medy
        # Perform sigma clipping out large positive outliers
        coef = dln.poly_fit(x[~m], y[~m], 2, robust=True)
        sig = dln.mad(y - dln.poly(x, coef))
        bd, nbd = dln.where((y - dln.poly(x, coef)) > 5 * sig)
        if nbd > 0: m[bd] = True
        gdmask = (y > 0) & (m == False)  # need positive fluxes and no mask set
        if np.sum(gdmask) == 0:
            continue
        # Bin the data points
        xr = [np.nanmin(x), np.nanmax(x)]
        bins = int(np.ceil((xr[1] - xr[0]) / binsize))
        ybin, bin_edges, binnumber = bindata.binned_statistic(
            x[gdmask],
            y[gdmask],
            statistic='percentile',
            percentile=perclevel,
            bins=bins,
            range=None)
        xbin = bin_edges[0:-1] + 0.5 * binsize
        # Interpolate to full grid
        if interp is True:
            fnt = np.isfinite(ybin)
            cont1 = dln.interp(xbin[fnt],
                               ybin[fnt],
                               x,
                               kind='quadratic',
                               extrapolate=True,
                               exporder=1)
        else:
            coef = dln.poly_fit(xbin, ybin, norder)
            cont1 = dln.poly(x, coef)
        cont1 *= medy
        cont[:, o] = cont1

    # Flatten to 1D if norder=1
    if spec.norder == 1:
        cont = cont.flatten()

    return cont
Exemplo n.º 4
0
    def __call__(self,
                 labels,
                 order=None,
                 norm=True,
                 fluxonly=False,
                 wave=None,
                 rv=None):
        # Default is to return all orders
        # order can also be a list or array of orders
        # Orders to loop over
        if order is None:
            orders = np.arange(self.norder)
        else:
            orders = list(np.atleast_1d(order))
        norders = dln.size(orders)
        # Get maximum number of pixels over all orders
        npix = 0
        for i in range(self.norder):
            npix = np.maximum(npix, self._data[i].dispersion.shape[0])
        # Wavelength array input
        if wave is not None:
            if wave.ndim == 1:
                wnorders = 1
            else:
                wnorders = wave.shape[1]
            if wnorders != norders:
                raise ValueError(
                    "Number of orders in WAVE must match orders in the model")
            npix = wave.shape[0]
        # Initialize output arrays
        oflux = np.zeros((npix, norders), np.float32) + np.nan
        owave = np.zeros((npix, norders), np.float64)
        omask = np.zeros((npix, norders), bool) + True
        # Order loop
        for i in orders:
            if wave is None:
                owave1 = self._data[
                    i].dispersion  # final wavelength array for this order
            else:
                if wave.ndim == 1:
                    owave1 = wave.copy()
                else:
                    owave1 = wave[:, i]
            # Get model and add radial velocity if necessary
            if (rv is None) & (wave is None):
                m = self._data[i]
                f = m(labels)
                zfactor = 1
            else:
                m = self._data_nointerp[i]
                f0 = m(labels)
                zfactor = 1 + rv / cspeed  # redshift factor
                zwave = m.dispersion * zfactor  # redshift the wavelengths
                f = np.zeros(len(owave1), np.float32) + np.nan
                gind, ngind = dln.where(
                    (owave1 >= np.min(zwave)) &
                    (owave1 <= np.max(zwave)))  # wavelengths we can cover
                if ngind > 0:
                    f[gind] = dln.interp(zwave, f0, owave1[gind])
            # Get Continuum
            if (norm is False):
                if hasattr(m, 'continuum'):
                    contmodel = m.continuum
                    smallcont = contmodel(labels)
                    if contmodel._logflux is True:
                        smallcont = 10**smallcont
                    # Interpolate to the full spectrum wavelength array
                    #   with any redshift
                    cont = dln.interp(contmodel.dispersion * zfactor,
                                      smallcont, owave1)
                    # Now mulitply the flux array by the continuum
                    f *= cont
                else:
                    raise ValueError(
                        "Model does not have continuum information")
            # Stuff in the array
            oflux[0:len(f), i] = f
            owave[0:len(f), i] = owave1
            omask[0:len(f), i] = False

        # Only return the flux
        if fluxonly is True: return oflux

        # Change single order 2D arrays to 1D
        if norders == 1:
            oflux = oflux.flatten()
            owave = owave.flatten()
            omask = omask.flatten()

        # Create Spec1D object
        mspec = Spec1D(oflux,
                       err=oflux * 0.0,
                       wave=owave,
                       mask=omask,
                       lsfsigma=None,
                       instrument='Model')
        mspec.teff = labels[0]
        mspec.logg = labels[1]
        mspec.feh = labels[2]
        #mspec.rv = rv
        mspec.snr = np.inf

        return mspec
Exemplo n.º 5
0
def prepare_cannon_model(model, spec, dointerp=False):
    """
    This prepares a Cannon model or list of models for an observed spectrum.
    The models are trimmed, rebinned, convolved to the spectrum LSF's and
    finally interpolated onto the spectrum's wavelength scale.

    The final interpolation can be omitted by setting dointerp=False (the default).
    This can be useful if the model is to interpolated multiple times on differen
    wavelength scales (e.g. for multiple velocities or logarithmic wavelength
    scales for cross-correlation).

    Parameters
    ----------
    model : Cannon model or list
       The Cannon model(s) to prepare for "spec".
    spec : Spec1D object
       The observed spectrum for which to prepare the Cannon model(s).
    dointerp : bool, optional
       Do the interpolation onto the observed wavelength scale.
       The default is False.

    Returns
    -------
    omodel : Cannon model or list
        The Cannon model or list of models prepared for "spec".

    Examples
    --------

    omodel = prepare_cannon_model(model,spec)

    """

    if spec.wave is None:
        raise Exception('No wavelength in observed spectrum')
    if spec.lsf is None:
        raise Exception('No LSF in observed spectrum')
    if type(model) is not list:
        if model.dispersion is None:
            raise Exception('No model wavelength information')

    if type(model) is list:
        outmodel = []
        for i in range(len(model)):
            model1 = model[i]
            omodel1 = prepare_cannon_model(model1, spec, dointerp=dointerp)
            outmodel.append(omodel1)
    else:

        # Convert wavelength from air->vacuum or vice versa
        if model.wavevac != spec.wavevac:
            # Air -> Vacuum
            if spec.wavevac is True:
                model.dispersion = astro.airtovac(model.dispersion)
                model.wavevac = True
            # Vacuum -> Air
            else:
                model.dispersion = astro.vactoair(model.dispersion)
                model.wavevac = False

        # Observed spectrum values
        wave = spec.wave
        ndim = wave.ndim
        if ndim == 2:
            npix, norder = wave.shape
        if ndim == 1:
            norder = 1
            npix = len(wave)
            wave = wave.reshape(npix, norder)
        # Loop over the orders
        outmodel = []
        for o in range(norder):
            w = wave[:, o]
            w0 = np.min(w)
            w1 = np.max(w)
            dw = dln.slope(w)
            dw = np.hstack((dw, dw[-1]))
            dw = np.abs(dw)
            meddw = np.median(dw)
            npix = len(w)

            if (np.min(model.dispersion) > w0) | (np.max(model.dispersion) <
                                                  w1):
                raise Exception(
                    'Model does not cover the observed wavelength range')

            # Trim
            nextend = int(np.ceil(len(w) * 0.25))  # extend 25% on each end
            nextend = np.maximum(nextend, 200)  # or 200 pixels
            if (np.min(model.dispersion) <
                (w0 - nextend * meddw)) | (np.max(model.dispersion) >
                                           (w1 + nextend * meddw)):
                tmodel = trim_cannon_model(model,
                                           w0=w0 - nextend * meddw,
                                           w1=w1 + nextend * meddw)
                #if (np.min(model.dispersion)<(w0-50*meddw)) | (np.max(model.dispersion)>(w1+50*meddw)):
                #    tmodel = trim_cannon_model(model,w0=w0-20*meddw,w1=w1+20*meddw)
                #if (np.min(model.dispersion)<(w0-1000.0*w0/cspeed)) | (np.max(model.dispersion)>(w1+1000.0*w1/cspeed)):
                #    # allow for up to 1000 km/s offset on each end
                #    tmodel = trim_cannon_model(model,w0=w0-1000.0*w0/cspeed,w1=w1+1000.0*w1/cspeed)
                tmodel.trim = True
            else:
                tmodel = cannon_copy(model)
                tmodel.trim = False

            # Rebin
            #  get LSF FWHM (A) for a handful of positions across the spectrum
            xp = np.arange(npix // 20) * 20
            fwhm = spec.lsf.fwhm(w[xp], xtype='Wave', order=o)
            # FWHM is in units of lsf.xtype, convert to wavelength/angstroms, if necessary
            if spec.lsf.xtype.lower().find('pix') > -1:
                dw1 = dln.interp(w, dw, w[xp], assume_sorted=False)
                fwhm *= dw1
            #  convert FWHM (A) in number of model pixels at those positions
            dwmod = dln.slope(tmodel.dispersion)
            dwmod = np.hstack((dwmod, dwmod[-1]))
            xpmod = interp1d(tmodel.dispersion,
                             np.arange(len(tmodel.dispersion)),
                             kind='cubic',
                             bounds_error=False,
                             fill_value=(np.nan, np.nan),
                             assume_sorted=False)(w[xp])
            xpmod = np.round(xpmod).astype(int)
            fwhmpix = fwhm / dwmod[xpmod]
            # need at least ~4 pixels per LSF FWHM across the spectrum
            #  using 3 affects the final profile shape
            nbin = np.round(np.min(fwhmpix) // 4).astype(int)
            if nbin == 0:
                import pdb
                nbin = 1
                print(spec.filename,
                      'Model has lower resolution than the observed spectrum',
                      fwhmpix.min())
                #raise Exception('Model has lower resolution than the observed spectrum',spec.filename,fwhmpix.min())
            if nbin > 1:
                rmodel = rebin_cannon_model(tmodel, nbin)
                rmodel.rebin = True
            else:
                rmodel = cannon_copy(tmodel)
                rmodel.rebin = False

            # Convolve
            lsf = spec.lsf.anyarray(rmodel.dispersion, xtype='Wave', order=o)

            #import pdb; pdb.set_trace()
            cmodel = convolve_cannon_model(rmodel, lsf)
            cmodel.convolve = True

            # Interpolate
            if dointerp is True:
                omodel = interp_cannon_model(cmodel, wout=spec.wave)
                omodel.interp = True
            else:
                omodel = cannon_copy(cmodel)
                omodel.interp = False

            # Order information
            omodel.norder = norder
            omodel.order = o

            #  # Copy continuum information
            #  if hasattr(model,'continuum'):
            #      omodel.continuum = cannon_copy(model.continuum)

            # Append to final output
            outmodel.append(omodel)

    # Single-element list
    if (type(outmodel) is list) & (len(outmodel) == 1):
        outmodel = outmodel[0]

    return outmodel
Exemplo n.º 6
0
    def normalize(self, ncorder=6, perclevel=0.95):
        """
        Normalize the spectrum.

        Parameters
        ----------
        ncorder : float, optional
              Polynomial order to use for the continuum fitting.
              The default is 6.
        perclevel : float, optional
              Percent level (1.0 for 100%) to use for the continuum value
              in large bins.  Default is 0.95.
              
        Returns
        -------
        The flux and err arrays will normalized (divided) by the continuum
        and the continuum saved in cont.  The normalized property is set to
        True.

        Examples
        --------

        spec.normalize()

        """

        self._flux = self.flux  # Save the original
        #nspec, cont, masked = normspec(self,ncorder=ncorder,perclevel=perclevel)

        binsize = 0.10
        perclevel = 90.0
        wave = self.wave.copy().reshape(self.npix, self.norder)  # make 2D
        flux = self.flux.copy().reshape(self.npix, self.norder)  # make 2D
        err = self.err.copy().reshape(self.npix, self.norder)  # make 2D
        mask = self.mask.copy().reshape(self.npix, self.norder)  # make 2D
        cont = err.copy() * 0.0 + 1
        for o in range(self.norder):
            w = wave[:, o].copy()
            x = (w - np.median(w)) / (np.max(w * 0.5) - np.min(w * 0.5)
                                      )  # -1 to +1
            y = flux[:, o].copy()
            m = mask[:, o].copy()
            # Divide by median
            medy = np.nanmedian(y)
            y /= medy
            # Perform sigma clipping out large positive outliers
            coef = dln.poly_fit(x, y, 2, robust=True)
            sig = dln.mad(y - dln.poly(x, coef))
            bd, nbd = dln.where((y - dln.poly(x, coef)) > 5 * sig)
            if nbd > 0: m[bd] = True
            gdmask = (y > 0) & (m == False
                                )  # need positive fluxes and no mask set
            # Bin the data points
            xr = [np.nanmin(x), np.nanmax(x)]
            bins = np.ceil((xr[1] - xr[0]) / binsize) + 1
            ybin, bin_edges, binnumber = bindata.binned_statistic(
                x[gdmask],
                y[gdmask],
                statistic='percentile',
                percentile=perclevel,
                bins=bins,
                range=None)
            xbin = bin_edges[0:-1] + 0.5 * binsize
            # Interpolate to full grid
            fnt = np.isfinite(ybin)
            cont1 = dln.interp(xbin[fnt], ybin[fnt], x, extrapolate=True)
            cont1 *= medy

            flux[:, o] /= cont1
            err[:, o] /= cont1
            cont[:, o] = cont1

        # Flatten to 1D if norder=1
        if self.norder == 1:
            flux = flux.flatten()
            err = err.flatten()
            cont = cont.flatten()

        # Stuff back in
        self.flux = flux
        self.err = err
        self.cont = cont
        self.normalized = True
        return
Exemplo n.º 7
0
def model_interp(teff, logg, metal, mtype='odfnew'):
    """ Interpolate Kurucz model."""

    availteff = np.arange(27) * 250 + 3500.0
    availlogg = np.arange(11) * .5 + 0.
    availmetal = np.arange(7) * 0.5 - 2.5

    if mtype is None:
        mtype = 'odfnew'
    if mtype == 'old':
        availmetal = np.arange(13) * 0.5 - 5.0

    if mtype == 'old':
        ntau = 64
    else:
        ntau = 72

    if mtype == 'odfnew' and teff > 10000:
        avail = Table.read(modeldir() + 'tefflogg.txt', format='ascii')
        avail['col1'].name = 'teff'
        avail['col2'].name = 'logg'
        availteff = avail['teff'].data
        availlogg = avail['logg'].data
        v1, nv1 = dln.where((abs(availteff - teff) < 0.1)
                            & (abs(availlogg - logg) <= 0.001))
        v2 = v1
        v3, nv3 = dln.where(abs(availmetal - metal) <= 0.001)
    else:
        v1, nv1 = dln.where(abs(availteff - teff) <= .1)
        v2, nv2 = dln.where(abs(availlogg - logg) <= 0.001)
        v3, nv3 = dln.where(abs(availmetal - metal) <= 0.001)

    # Linear Interpolation
    teffimif = max(np.where(availteff <= teff)[0])  # immediately inferior Teff
    loggimif = max(np.where(availlogg <= logg)[0])  # immediately inferior logg
    metalimif = max(
        np.where(availmetal <= metal)[0])  #immediately inferior [Fe/H]
    teffimsu = min(np.where(availteff >= teff)[0])  # immediately superior Teff
    loggimsu = min(np.where(availlogg >= logg)[0])  # immediately superior logg
    metalimsu = min(
        np.where(availmetal >= metal)[0])  #immediately superior [Fe/H]

    if mtype == 'old':
        ncols = 7
    else:
        ncols = 10

    grid = np.zeros((2, 2, 2, ncols), dtype=np.float64)
    tm1 = availteff[teffimif]
    tp1 = availteff[teffimsu]
    lm1 = availlogg[loggimif]
    lp1 = availlogg[loggimsu]
    mm1 = availmetal[metalimif]
    mp1 = availmetal[metalimsu]

    if (tp1 != tm1):
        mapteff = (teff - tm1) / (tp1 - tm1)
    else:
        mapteff = 0.5
    if (lp1 != lm1):
        maplogg = (logg - lm1) / (lp1 - lm1)
    else:
        maplogg = 0.5
    if (mp1 != mm1):
        mapmetal = (metal - mm1) / (mp1 - mm1)
    else:
        mapmetal = 0.5

    # Reading the corresponding models
    for i in np.arange(8) + 1:
        if i == 1:
            model, header, tail = read_kurucz(tm1, lm1, mm1, mtype=mtype)
        if i == 2: model, h, t = read_kurucz(tm1, lm1, mp1, mtype=mtype)
        if i == 3: model, h, t = read_kurucz(tm1, lp1, mm1, mtype=mtype)
        if i == 4: model, h, t = read_kurucz(tm1, lp1, mp1, mtype=mtype)
        if i == 5: model, h, t = read_kurucz(tp1, lm1, mm1, mtype=mtype)
        if i == 6: model, h, t = read_kurucz(tp1, lm1, mp1, mtype=mtype)
        if i == 7: model, h, t = read_kurucz(tp1, lp1, mm1, mtype=mtype)
        if i == 8: model, h, t = read_kurucz(tp1, lp1, mp1, mtype=mtype)

        if (len(model[0, :]) > ntau):
            m2 = np.zeros((ncols, ntau), dtype=np.float64)
            m2[0, :] = interpol(model[0, :], ntau)
            for j in range(ncols):
                m2[j, :] = interpol(model[j, :], model[0, :], m2[0, :])
            model = m2

# getting the tauross scale
        rhox = model[0, :]
        kappaross = model[4, :]
        tauross = np.zeros(ntau, dtype=np.float64)
        tauross[0] = rhox[0] * kappaross[0]
        for ii in np.arange(ntau - 1) + 1:
            tauross[ii] = trapz(rhox[0:ii + 1], kappaross[0:ii + 1])

        if i == 1:
            model1 = model
            tauross1 = tauross
        elif i == 2:
            model2 = model
            tauross2 = tauross
        elif i == 3:
            model3 = model
            tauross3 = tauross
        elif i == 4:
            model4 = model
            tauross4 = tauross
        elif i == 5:
            model5 = model
            tauross5 = tauross
        elif i == 6:
            model6 = model
            tauross6 = tauross
        elif i == 7:
            model7 = model
            tauross7 = tauross
        elif i == 8:
            model8 = model
            tauross8 = tauross
        else:
            print('% KMOD: i should be 1--8!')

    model = np.zeros((ncols, ntau),
                     dtype=np.float64)  # cleaning up for re-using the matrix

    # Defining the mass (RHOX#gr cm-2) sampling
    tauross = tauross1  # re-using the vector tauross
    bot_tauross = min([
        tauross1[ntau - 1], tauross2[ntau - 1], tauross3[ntau - 1],
        tauross4[ntau - 1], tauross5[ntau - 1], tauross6[ntau - 1],
        tauross7[ntau - 1], tauross8[ntau - 1]
    ])
    top_tauross = max([
        tauross1[0], tauross2[0], tauross3[0], tauross4[0], tauross5[0],
        tauross6[0], tauross7[0], tauross8[0]
    ])
    g, = np.where((tauross >= top_tauross) & (tauross <= bot_tauross))
    tauross_new = dln.interp(np.linspace(0, 1, len(g)),
                             tauross[g],
                             np.linspace(0, 1, ntau),
                             kind='linear')

    # Let's interpolate for every depth
    points = (np.arange(2), np.arange(2), np.arange(2))
    for i in np.arange(ntau - 1) + 1:
        for j in range(ncols):
            grid[0, 0, 0, j] = dln.interp(tauross1[1:],
                                          model1[j, 1:],
                                          tauross_new[i],
                                          kind='linear')
            grid[0, 0, 1, j] = dln.interp(tauross2[1:],
                                          model2[j, 1:],
                                          tauross_new[i],
                                          kind='linear')
            grid[0, 1, 0, j] = dln.interp(tauross3[1:],
                                          model3[j, 1:],
                                          tauross_new[i],
                                          kind='linear')
            grid[0, 1, 1, j] = dln.interp(tauross4[1:],
                                          model4[j, 1:],
                                          tauross_new[i],
                                          kind='linear')
            grid[1, 0, 0, j] = dln.interp(tauross5[1:],
                                          model5[j, 1:],
                                          tauross_new[i],
                                          kind='linear')
            grid[1, 0, 1, j] = dln.interp(tauross6[1:],
                                          model6[j, 1:],
                                          tauross_new[i],
                                          kind='linear')
            grid[1, 1, 0, j] = dln.interp(tauross7[1:],
                                          model7[j, 1:],
                                          tauross_new[i],
                                          kind='linear')
            grid[1, 1, 1, j] = dln.interp(tauross8[1:],
                                          model8[j, 1:],
                                          tauross_new[i],
                                          kind='linear')
            model[j, i] = interpn(points,
                                  grid[:, :, :, j],
                                  (mapteff, maplogg, mapmetal),
                                  method='linear')

    for j in range(ncols):
        model[j, 0] = model[j, 1] * 0.999

    # Editing the header
    header[0] = strput(header[0], '%7.0f' % teff, 4)
    header[0] = strput(header[0], '%8.5f' % logg, 21)

    tmpstr1 = header[1]
    tmpstr2 = header[4]
    if (metal < 0.0):
        if type == 'old':
            header[1] = strput(header[1], '-%3.1f' % abs(metal), 18)
        else:
            header[1] = strput(header[1], '-%3.1f' % abs(metal), 8)
        header[4] = strput(header[4], '%9.5f' % 10**metal, 16)
    else:
        if type == 'old':
            header[1] = strput(header[1], '+%3.1f' % abs(metal), 18)
        else:
            header[1] = strput(header[1], '+%3.1f' % abs(metal), 8)
        header[4] = strput(header[4], '%9.5f' % 10**metal, 16)
    header[22] = strput(header[22], '%2i' % ntau, 11)

    return model, header, tail
Exemplo n.º 8
0
 lag = np.arange(2 * maxlag + 1) - maxlag
 rflux = refspec.spec1d_flux.value
 rflux[refspec.spec1d_uncertainty.quantity.value > 900] = np.nan
 sflux = spec.spec1d_flux.value
 sflux[spec.spec1d_uncertainty.quantity.value > 900] = np.nan
 # cross-correlate chunks
 nchunks = 5
 xshift = np.zeros(nchunks, float)
 mnx = np.zeros(nchunks, float)
 nbin = npix // nchunks
 for k in range(nchunks):
     mnx[k] = np.mean([k * nbin, (k + 1) * nbin - 1])
     cc = ccorrelate(rflux[k * nbin:(k + 1) * nbin],
                     sflux[k * nbin:(k + 1) * nbin], lag)
     lag2 = np.linspace(-maxlag, maxlag, 1000)
     cc2 = dln.interp(lag, cc, lag2)
     bestshift = lag2[np.argmax(cc2)]
     xshift[k] = bestshift
 print('shifts = ' + str(xshift))
 cc = ccorrelate(rflux, sflux, lag)
 lag2 = np.linspace(-maxlag, maxlag, 1000)
 cc2 = dln.interp(lag, cc, lag2)
 bestshift = lag2[np.argmax(cc2)]
 print('best shift = ' + str(bestshift))
 # Shift reference wavelength array
 refwav = refap.func(x)
 drefwav = refwav[1:] - refwav[0:-1]
 drefwav = np.append(drefwav, drefwav[-1])
 xshiftall = dln.interp(mnx, xshift, np.arange(npix))
 #wav0 = refwav.copy() - drefwav*xshiftall
 wav0 = refwav.copy() - drefwav * bestshift
Exemplo n.º 9
0
def getaplines(idlines,apinfo,ap,diag=False):

    #aperture = [id.aperture for id in idlines]
    #aperture = np.array(aperture)
    apind, = np.where(apinfo['aperture']==ap)
    apind = apind[0]
    idline1 = idlines[apind]

    goodap, = np.where(apinfo['good']==True)
    
    # This is a "good" aperture
    if apind in goodap:
        #print(str(ap)+' is a good aperture')
        nlines = len(idline1.fit_lines.fit)
        linecat = np.zeros(nlines,dtype=np.dtype([('aperture',int),('num',int),('height',float),('center',float),
                                                  ('sigma',float),('wave0',float),('wave',float),('match',int),('outlier',bool)]))
        linecat['aperture'][:] = idline1.aperture
        linecat['num'][:] = np.arange(nlines)+1
        for j in range(nlines):
            linecat['height'][j] = idline1.fit_lines.fit[j].parameters[0]
            linecat['center'][j] = idline1.fit_lines.fit[j].parameters[1]
            linecat['sigma'][j] = idline1.fit_lines.fit[j].parameters[2]
            wav = idline1.wav[j]
            if isinstance(wav,float):
                linecat['wave'][j] = wav
                linecat['match'][j] = 1
        return linecat

    print(str(ap)+' is a bad aperture')
    
    # This is a "bad" aperture
    spec = extract1d_array[apind]
    # Find a neighboring good aperture
    bestind = goodap[np.argmin(np.abs(apinfo['aperture'][apind]-apinfo['aperture'][goodap]))]
    #if idline1.aperture==61:
    #    bestind = 62
    print('Best reference aperture: '+str(apinfo['aperture'][bestind]))
    refap = idlines[bestind]
    refspec = extract1d_array[bestind]
    # Cross-correlate the spectra to get shift
    maxlag = 10
    lag = np.arange(2*maxlag+1)-maxlag
    rflux = refspec.spec1d_flux.value
    rflux[refspec.spec1d_uncertainty.quantity.value>900] = np.nan
    sflux = spec.spec1d_flux.value
    sflux[spec.spec1d_uncertainty.quantity.value>900] = np.nan        
    # cross-correlate chunks
    nchunks = 5
    xshift = np.zeros(nchunks,float)
    mnx = np.zeros(nchunks,float)
    nbin = npix//nchunks
    for k in range(nchunks):
        mnx[k] = np.mean([k*nbin,(k+1)*nbin-1])
        cc = ccorrelate(rflux[k*nbin:(k+1)*nbin],sflux[k*nbin:(k+1)*nbin],lag)
        lag2 = np.linspace(-maxlag,maxlag,1000)
        cc2 = dln.interp(lag,cc,lag2)
        bestshift = lag2[np.argmax(cc2)]
        xshift[k] = bestshift
    print('shifts = '+str(xshift))
    cc = ccorrelate(rflux,sflux,lag)
    lag2 = np.linspace(-maxlag,maxlag,1000)
    cc2 = dln.interp(lag,cc,lag2)
    bestshift = lag2[np.argmax(cc2)]        
    print('best shift = '+str(bestshift))

    #if ap==61:
    #    #plt.plot(x,rflux)
    #    #plt.plot(x+bestshift,sflux)
    #    #plt.show()
    #    #import pdb; pdb.set_trace()
    #    print('KLUDGE for aperture 61')
    #    bestshift = 0.0
        
    if diag==True:
        plt.plot(x,rflux)
        plt.plot(x-bestshift,sflux)
        plt.show()
    
    # Shift reference wavelength array
    refwav = refap.func(x)
    drefwav = refwav[1:]-refwav[0:-1]
    drefwav = np.append(drefwav,drefwav[-1])
    xshiftall = dln.interp(mnx,xshift,np.arange(npix))
    #wav0 = refwav.copy() - drefwav*xshiftall
    wav0 = refwav.copy() - drefwav*bestshift        
    # Get initial wavelengths for the lines
    nlines = len(idline1.fit_lines.fit)
    linecat = np.zeros(nlines,dtype=np.dtype([('aperture',int),('num',int),('height',float),('center',float),
                                              ('sigma',float),('wave0',float),('wave',float),('match',int),('outlier',bool)]))
    linecat['aperture'][:] = idline1.aperture
    linecat['num'][:] = np.arange(nlines)+1
    for j in range(nlines):
        linecat['height'][j] = idline1.fit_lines.fit[j].parameters[0]
        linecat['center'][j] = idline1.fit_lines.fit[j].parameters[1]
        linecat['sigma'][j] = idline1.fit_lines.fit[j].parameters[2]            
    linecat['wave0'][:] = dln.interp(x,wav0,linecat['center'])
    # Try to ID them using the template lines
    match = np.zeros(ntlines,int)-1
    dwave = np.zeros(ntlines,float)-1
    for j in range(ntlines):
        bestline = np.argmin(np.abs(tlinecat['wave'][j]-linecat['wave0']))
        maxdiff = 0.5  #1.0
        if np.abs(tlinecat['wave'][j]-linecat['wave0'][bestline])<maxdiff:
            match[j] = bestline
            dwave[j] = tlinecat['wave'][j]-linecat['wave0'][bestline]
    gmatch, = np.where(match>-1)
    linecat['wave'][match[gmatch]] = tlinecat['wave'][gmatch]
    linecat['match'][match[gmatch]] = 1

    return linecat
Exemplo n.º 10
0
def skytweak(extfile,skyfile,plugfile,diag=False):
    """ Tweak the Sky subtraction."""

    #extfile = 'ut20131123/b0236_extract1d_array.pickle'
    #skyfile = 'ut20131123/b0236_sky_array.pickle'
    #plugfile = 'ut20131123/b0236_plugmap.pickle'

    print('Tweaking sky subtraction')
    print('extract1d file = '+extfile)
    print('sky file = '+skyfile)
    print('plugmap file = '+plugfile)    
    
    if os.path.exists(extfile)==False:
        raise ValueError(extfile+' NOT FOUND')
    if os.path.exists(skyfile)==False:
        raise ValueError(skyfile+' NOT FOUND')
    if os.path.exists(plugfile)==False:
        raise ValueError(plugfile+' NOT FOUND')    
    
    ext = pickle.load(open(extfile,'rb'))    
    sky = pickle.load(open(skyfile,'rb'))
    plugmap = pickle.load(open(plugfile,'rb'))

    #skysub = pickle.load(open('ut20131123/b0236_skysubtract_array.pickle','rb'))
    #ext1d = pickle.load(open('ut20131123/b0236_extract1d_array.pickle','rb'))
    #ext = pickle.load(open('ut20131123/b0236_throughputcorr_array.pickle','rb'))
    #thru = pickle.load(open('ut20131123/b0236_throughput_array.pickle','rb'))
    #plugmap = pickle.load(open('ut20131123/b0236_plugmap.pickle','rb')) 
    
    nap = len(ext)
    outsky = []
    outskysub = []
    outscale = []
    # Loop over apertures
    for i in range(nap):
        ext1 = ext[i]
        sky1 = sky[i]
        if np.nansum(sky1.spec1d_flux.value)>0:
            skycont = get_continuum(sky1.spec1d_flux.value)
            mask = ((sky1.spec1d_flux.value-skycont) > 25) & np.isfinite(ext1.spec1d_flux.value) & np.isfinite(sky1.spec1d_flux.value)
        
            scaling = np.linspace(0.2,2.0,50)
            resid = np.zeros(len(scaling),float)
            for j in range(len(scaling)):
                resid[j] = skyresid(ext1.spec1d_flux.value,sky1.spec1d_flux.value,scaling[j],mask)
            scaling2 = np.linspace(0.2,2.0,1000)
            resid2 = dln.interp(scaling,resid,scaling2)
            bestind = np.argmin(np.abs(resid2))
            bestscale = scaling2[bestind]
            print(str(i+1)+' '+str(bestscale))
            outscale.append(bestscale)
            outsky1 = deepcopy(sky1)
            outsky1.spec1d_flux *= bestscale
            outsky1.spec1d_uncertainty.array *= bestscale            
            outsky.append(outsky1)
            outskysub1 = deepcopy(ext1)
            outskysub1.spec1d_flux -= outsky1.spec1d_flux
            outskysub.append(outskysub1)

            eflux = ext1.spec1d_flux.value.copy()
            sflux = sky1.spec1d_flux.value.copy()
            bestresid = eflux-sflux*bestscale
            # Fit continuum and subtract
            bestcont = get_continuum(bestresid)
    
            if diag==True:
                eflux[(~np.isfinite(eflux)) | (ext1.spec1d_uncertainty.quantity.value>900)] = np.nan                
                fig = plt.figure(figsize=(10,8))
                #fig,ax = plt.subplots()
                #fig.set_figheight(8)
                #fig.set_figwidth(10)
                plt.plot(eflux)
                plt.plot(bestcont)
                plt.plot(outsky1.spec1d_flux.value+bestcont,alpha=0.7)
                plt.plot([0,2048],[0,0],linestyle='--',c='gray',alpha=0.8)
                #plt.plot(outsky1.spec1d_flux)
                plt.plot(outskysub1.spec1d_flux.value-150)
                plt.plot(bestcont-150)
                plt.plot([0,2048],[-150,-150],linestyle='--',c='gray',alpha=0.8)
                plt.xlabel('X')
                plt.ylabel('Flux')
                plt.xlim(0,2048)
                plt.ylim(-400,800)
                plt.title('Aperture '+str(ext1.aperture)+' Scale=%5.2f' % bestscale)
                plt.show()
        else:
            print(str(i+1)+' skipping')
            outscale.append(1.0)
            outsky.append(sky1)
            outskysub.append(ext1)
            
    return outscale,outsky,outskysub