Пример #1
0
def plotspec(spec,spec2=None,model=None,figsize=10):
    """ Plot a spectrum."""
    norder = spec.norder
    fig = plt.gcf()   # get current graphics window
    fig.clf()         # clear
    # Single-order plot
    if norder==1:
        ax = fig.subplots()
        fig.set_figheight(figsize*0.5)
        fig.set_figwidth(figsize)
        plt.plot(spec.wave,spec.flux,'b',label='Spectrum 1',linewidth=1)
        if spec2 is not None:
            plt.plot(spec2.wave,spec2.flux,'green',label='Spectrum 2',linewidth=1)            
        if model is not None:
            plt.plot(model.wave,model.flux,'r',label='Model',linewidth=1,alpha=0.8)
        leg = ax.legend(loc='upper left', frameon=False)
        plt.xlabel('Wavelength (Angstroms)')
        plt.ylabel('Normalized Flux')
        xr = dln.minmax(spec.wave)
        allflux = spec.flux.flatten()
        if spec2 is not None:
            allflux = np.concatenate((allflux,spec2.flux.flatten()))
        if model is not None:
            allflux = np.concatenate((allflux,model.flux.flatten()))                
        yr = [np.min(allflux), np.max(allflux)]
        yr = [yr[0]-dln.valrange(yr)*0.15,yr[1]+dln.valrange(yr)*0.005]
        yr = [np.max([yr[0],-0.2]), np.min([yr[1],2.0])]
        plt.xlim(xr)
        plt.ylim(yr)
    # Multi-order plot
    else:
        ax = fig.subplots(norder)
        fig.set_figheight(figsize)
        fig.set_figwidth(figsize)
        for i in range(norder):
            ax[i].plot(spec.wave[:,i],spec.flux[:,i],'b',label='Spectrum 1',linewidth=1)
            if spec2 is not None:
                ax[i].plot(spec2.wave[:,i],spec2.flux[:,i],'green',label='Spectrum 2',linewidth=1)                        
            if model is not None:
                ax[i].plot(model.wave[:,i],model.flux[:,i],'r',label='Model',linewidth=1,alpha=0.8)
            if i==0:
                leg = ax[i].legend(loc='upper left', frameon=False)
            ax[i].set_xlabel('Wavelength (Angstroms)')
            ax[i].set_ylabel('Normalized Flux')
            xr = dln.minmax(spec.wave[:,i])
            allflux = spec.flux[:,i].flatten()
            if spec2 is not None:
                allflux = np.concatenate((allflux,spec2.flux[:,i].flatten()))
            if model is not None:
                allflux = np.concatenate((allflux,model.flux[:,i].flatten()))                
            yr = [np.min(allflux), np.max(allflux)]
            yr = [yr[0]-dln.valrange(yr)*0.05,yr[1]+dln.valrange(yr)*0.05]
            if i==0:
                yr = [yr[0]-dln.valrange(yr)*0.15,yr[1]+dln.valrange(yr)*0.05]            
            yr = [np.max([yr[0],-0.2]), np.min([yr[1],2.0])]
            ax[i].set_xlim(xr)
            ax[i].set_ylim(yr)
Пример #2
0
def plotfit(cat, pars, cov, savefig=None):
    """ Plot a figure of the data and the proper motion/parallax fit."""

    plt.rcParams.update({'font.size': 12})

    # Compute relative positions
    cenra = np.mean(cat['ra'])
    cendec = np.mean(cat['dec'])
    lon, lat = dcoords.rotsphcen(cat['ra'],
                                 cat['dec'],
                                 cenra,
                                 cendec,
                                 gnomic=True)
    lon *= d2a
    lat *= d2a

    # Array of MJDs for model curve
    mjd = np.linspace(np.min(cat['mjd']), np.max(cat['mjd']), 100)
    out = astrometryfunc([cenra, cendec, mjd], pars[0], pars[1], pars[2],
                         pars[3], pars[4])
    ll = out[0:100]
    bb = out[100:]

    # Plot the model and data
    plt.plot(ll, bb)
    plt.errorbar(lon,
                 lat,
                 xerr=cat['raerr'],
                 yerr=cat['decerr'],
                 fmt='o',
                 color='black',
                 markersize=5,
                 ecolor='lightgray',
                 elinewidth=2,
                 linestyle='none',
                 capsize=0)
    plt.xlabel('dRA (arcsec)')
    plt.ylabel('dDEC (arcsec)')
    xr = dln.minmax(np.concatenate((lon, ll)))
    xr = [xr[0] - 0.05 * dln.valrange(xr), xr[1] + 0.05 * dln.valrange(xr)]
    yr = dln.minmax(np.concatenate((lat, bb)))
    yr = [yr[0] - 0.05 * dln.valrange(yr), yr[1] + 0.05 * dln.valrange(yr)]
    plt.xlim(xr)
    plt.ylim(yr)
    perr = np.sqrt(np.diag(cov))
    plt.annotate(
        r'$\mu_\alpha$ = %5.3f $\pm$ %5.3f mas/yr' %
        (pars[2] * 1e3, perr[2] * 1e3) + '\n' +
        r'$\mu_\delta$ = %5.3f $\pm$ %5.3f mas/yr' %
        (pars[3] * 1e3, perr[3] * 1e3) + '\n' +
        r'$\pi$ = %5.3f $\pm$ %5.3f mas' % (pars[4] * 1e3, perr[4] * 1e3),
        xy=(xr[0] + 0.05 * dln.valrange(xr), yr[1] - 0.20 * dln.valrange(yr)),
        ha='left')
    if savefig is not None:
        plt.savefig(savefig)
Пример #3
0
def load_cannon_model(files):
    """
    Load a single (or list of) Cannon models from file and manipulate as needed.

    Returns
    -------
    files : string
       File name (or list of filenames) of Cannon models to load.

    Examples
    --------
    model = load_cannon_model()

    """

    # Convert single string into a list
    if type(files) is not list: files = list(np.atleast_1d(files))

    model = []
    for f in files:
        if os.path.exists(f) == False:
            raise ValueError(f + ' not found')
        model1 = tc.CannonModel.read(f)
        # Generate the model ranges
        ranges = np.zeros([3, 2])
        for i in range(3):
            ranges[i, :] = dln.minmax(model1._training_set_labels[:, i])
        model1.ranges = ranges
        # Rename _fwhm to fwhm and _wavevac to wavevac
        if hasattr(model1, '_fwhm'):
            setattr(model1, 'fwhm', model1._fwhm)
            delattr(model1, '_fwhm')
        if hasattr(model1, '_wavevac'):
            setattr(model1, 'wavevac', model1._wavevac)
            delattr(model1, '_wavevac')
        # Create continuum model if the information is there
        if hasattr(model1, '_continuum'):
            contmodel = readfromdata(model1._continuum)
            model1.continuum = contmodel
            delattr(model1, '_continuum')
        # Convert to DopplerCannonModel
        model.append(DopplerCannonModel(model1))

    if len(model) == 1: model = model[0]
    return model
Пример #4
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
Пример #5
0
def make_logwave_scale(wave, vel=1000.0):
    """
    Create a logarithmic wavelength scale for a given wavelength array.

    This is used by rv.fit() to create a logarithmic wavelength scale for
    cross-correlation.

    If the input wavelength array is 2D with multiple orders (trailing
    dimension), then the output wavelength array will extend beyond the
    boundaries of some of the orders.  These pixels will have to be
    "padded" with dummy/masked-out pixels.

    Parameters
    ----------
    wave : array
         Input wavelength array, 1D or 2D with multiple orders.
    vel : float, optional
         Maximum velocity shift to allow for.  Default is 1000.

    Returns
    -------
    fwave : array
         New logarithmic wavelength array.

    Example
    -------
    .. code-block:: python

         fwave = make_logwave_scale(wave)

    """

    # If the existing wavelength scale is logarithmic then use it, just extend
    # on either side
    vel = np.abs(vel)
    wave = np.float64(wave)
    nw = len(wave)
    wr = dln.minmax(wave)

    # Multi-order wavelength array
    if wave.ndim == 2:
        norder = wave.shape[1]

        # Ranges
        wr = np.empty((2, norder), np.float64)
        wlo = np.empty(norder, np.float64)
        whi = np.empty(norder, np.float64)
        for i in range(norder):
            wr[:, i] = dln.minmax(wave[:, i])
            wlo[i] = wr[0, i] - vel / cspeed * wr[0, i]
            whi[i] = wr[1, i] + vel / cspeed * wr[1, i]

        # For multi-order wavelengths, the final wavelength solution will extend
        # beyond the boundary of the original wavelength solution (at the end).
        # The extra pixels will have to be "padded" with masked out values.

        # We want the same logarithmic step for all order
        dw = np.log10(np.float64(wave[1:, :])) - np.log10(
            np.float64(wave[0:-1, :]))
        dwlog = np.median(np.abs(dw))  # positive

        # Extend at the ends
        if vel > 0:
            nlo = np.empty(norder, int)
            nhi = np.empty(norder, int)
            for i in range(norder):
                nlo[i] = np.int(
                    np.ceil((np.log10(np.float64(wr[0, i])) -
                             np.log10(np.float64(wlo[i]))) / dwlog))
                nhi[i] = np.int(
                    np.ceil((np.log10(np.float64(whi[i])) -
                             np.log10(np.float64(wr[1, i]))) / dwlog))
            # Use the maximum over all orders
            nlo = np.max(nlo)
            nhi = np.max(nhi)
        else:
            nlo = 0
            nhi = 0

        # Number of pixels for the input wavelength range
        n = np.empty(norder, int)
        for i in range(norder):
            if vel == 0:
                n[i] = np.int((np.log10(np.float64(wr[1, i])) -
                               np.log10(np.float64(wr[0, i]))) / dwlog)
            else:
                n[i] = np.int(
                    np.ceil((np.log10(np.float64(wr[1, i])) -
                             np.log10(np.float64(wr[0, i]))) / dwlog))
        # maximum over all orders
        n = np.max(n)

        # Final number of pixels
        nf = n + nlo + nhi

        # Final wavelength array
        fwave = np.empty((nf, norder), np.float64)
        for i in range(norder):
            fwave[:, i] = 10**((np.arange(nf) - nlo) * dwlog +
                               np.log10(np.float64(wr[0, i])))

        # Make sure the element that's associated with the first input wavelength is identical
        for i in range(norder):
            # Increasing input wavelength arrays
            if np.median(dw[:, i]) > 0:
                fwave[:, i] -= fwave[nlo, i] - wave[0, i]
            # Decreasing input wavelength arrays
            else:
                fwave[:, i] -= fwave[nlo, i] - wave[-1, i]

    # Single-order wavelength array
    else:
        # extend wavelength range by +/-vel km/s
        wlo = wr[0] - vel / cspeed * wr[0]
        whi = wr[1] + vel / cspeed * wr[1]

        # logarithmic step
        dwlog = np.median(dln.slope(np.log10(np.float64(wave))))

        # extend at the ends
        if vel > 0:
            nlo = np.int(
                np.ceil(
                    (np.log10(np.float64(wr[0])) - np.log10(np.float64(wlo))) /
                    dwlog))
            nhi = np.int(
                np.ceil(
                    (np.log10(np.float64(whi)) - np.log10(np.float64(wr[1]))) /
                    dwlog))
        else:
            nlo = 0
            nhi = 0

        # Number of pixels
        if vel == 0.0:
            n = np.int(
                (np.log10(np.float64(wr[1])) - np.log10(np.float64(wr[0]))) /
                dwlog)
        else:
            n = np.int(
                np.ceil(
                    (np.log10(np.float64(wr[1])) - np.log10(np.float64(wr[0])))
                    / dwlog))
        nf = n + nlo + nhi

        fwave = 10**((np.arange(nf) - nlo) * dwlog +
                     np.log10(np.float64(wr[0])))

        # Make sure the element that's associated with the first input wavelength is identical
        fwave -= fwave[nlo] - wave[0]

    # w=10**(w0log+i*dwlog)
    return fwave
    # expand by a fraction, it's not an extact boundary but good enough
    buffsize = 10.0 / 3600.  # in deg
    radbound = np.sqrt(lonbound**2 + latbound**2)
    frac = 1.0 + 1.5 * np.max(buffsize / radbound)
    lonbuff = lonbound * frac
    latbuff = latbound * frac
    rabuff, decbuff = coords.rotsphcen(lonbuff,
                                       latbuff,
                                       cenra,
                                       cendec,
                                       gnomic=True,
                                       reverse=True)
    if (np.max(rabuff) - np.min(rabuff)) > 100:  # deal with RA=0 wraparound
        bd, = np.where(rabuff > 180)
        if len(bd) > 0: rabuff[bd] -= 360.0
    buffdict = {'cenra':cenra,'cendec':cendec,'rar':utils.minmax(rabuff),'decr':utils.minmax(decbuff),'ra':rabuff,'dec':decbuff,\
                'lon':lonbuff,'lat':latbuff,'lr':utils.minmax(lonbuff),'br':utils.minmax(latbuff)}

    # Initialize the ID structure
    # this will contain the MeasID, Exposure name, ObjectID
    dtype_idstr = np.dtype([('measid', np.str, 200), ('exposure', np.str, 200),
                            ('expnum', np.str, 200), ('objectid', np.str, 200),
                            ('objectindex', int)])
    idstr = np.zeros(1000000, dtype=dtype_idstr)
    nidstr = len(idstr)
    idcnt = 0

    # Initialize the object structure
    dtype_obj = np.dtype([('objectid', np.str, 100), ('pix', int),
                          ('ra', np.float64), ('dec', np.float64),
                          ('raerr', float), ('decerr', float), ('pmra', float),
Пример #7
0
def starcube(cat,image,npix=51,fillvalue=np.nan):
    """
    Produce a cube of cutouts of stars.

    Parameters
    ----------
    cat : table
       The catalog of stars to use.  This should have "x" and "y" columns and
         preferably also "amp".
    image : CCDData object
       The image to use to generate the stellar images.
    fillvalue : float, optional
       The fill value to use for pixels that are bad are off the image.
            Default is np.nan.

    Returns
    -------
    cube : numpy array
       Two-dimensional cube (Npix,Npix,Nstars) of the star images.

    Example
    -------

    cube = starcube(cat,image)

    """

    # Get the residuals data
    nstars = len(cat)
    nhpix = npix//2
    cube = np.zeros((npix,npix,nstars),float)
    xx,yy = np.meshgrid(np.arange(npix)-nhpix,np.arange(npix)-nhpix)
    rr = np.sqrt(xx**2+yy**2)        
    x = xx[0,:]
    y = yy[:,0]
    for i in range(nstars):
        xcen = cat['x'][i]            
        ycen = cat['y'][i]
        bbox = models.starbbox((xcen,ycen),image.shape,nhpix)
        im = image[bbox.slices]
        flux = image.data[bbox.slices]-image.sky[bbox.slices]
        err = image.error[bbox.slices]
        if 'amp' in cat.columns:
            amp = cat['amp'][i]
        elif 'peak' in cat.columns:
            amp = cat['peak'][i]
        else:
            amp = flux[int(np.round(ycen)),int(np.round(xcen))]
        xim,yim = np.meshgrid(im.x,im.y)
        xim = xim.astype(float)-xcen
        yim = yim.astype(float)-ycen
        # We need to interpolate this onto the grid
        f = RectBivariateSpline(yim[:,0],xim[0,:],flux/amp)
        im2 = np.zeros((npix,npix),float)+np.nan
        xcover = (x>=bbox.ixmin-xcen) & (x<=bbox.ixmax-1-xcen)
        xmin,xmax = dln.minmax(np.where(xcover)[0])
        ycover = (y>=bbox.iymin-ycen) & (y<=bbox.iymax-1-ycen)
        ymin,ymax = dln.minmax(np.where(ycover)[0])            
        im2[ymin:ymax+1,xmin:xmax+1] = f(y[ycover],x[xcover],grid=True)
        # Stuff it into 3D array
        cube[:,:,i] = im2
    return cube
Пример #8
0
    cfile = cfile.replace('/net/mss1/','')
    cfile = cfile.replace('/mss1/','')
    # Fixing very negative RAs
    print('FIXING NEGATIVE RAs in CALSTR and CHSTR')
    #bdra, = np.where(chstr.cenra lt -180,nbdra)
    bdra,nbdra = dln.where(chstr['cenra']<0)
    dum,uibd = np.unique(chstr['expdir'][bdra],return_indices=True)
    ind1,ind2 = dln.match(calstr['expdir'],chstr['expdir'][bdra[uibd]])
    nmatch = len(ind1)
    for i in range(nmatch):
        ind3,ind4 = dln.match(chstr['expdir'][bdra],calstr['expdir'][ind1[i]])
        # Fix CALSTR RA
        chra = chstr['cenra'][bdra[ind3]]
        bd1,nbd1 = dln.where(chra < -180)
        if nbd1>0: chra[bd1]+=360
        cenra = np.mean(dln.minmax(chra))
        if cenra<0: cenra+=360
        calstr['ra'][ind1[i]] = cenra
        # Fix CHSTR CENRA
        bd2,nbd2 = dln.where(chra<0)
        if nbd2>0: chra[bd2]+=360
        chstr['cenra'][bdra[ind3]] = chra
        # Fix CHSTR VRA
        vra = chstr['vra'][bdra[ind3]]
        bd3,nbd3 = dln.where(vra<0)
        if nbd3>0: vra[bd3]+=360
        chstr['vra'][bdra[ind3]] = vra

    # Fix instrument in STR and CHSTR
    print('FIXING INSTRUMENT IN STR AND CHSTR')
    type = ['c4d','k4m','ksb']