Example #1
0
def read_spectra(spplate_name, targetids=None, use_frames=False,
    fiberid=None, coadd=False):
    """Read targets from a list of spectra files

    Args:
        spplate_name (str): input spPlate file
        targetids (list): restrict targets to this subset.
        use_frames (bool): if True, use frames.
        fiberid (int): Use this fiber ID.
        coadd (bool): if True, compute and use the coadds.

    Returns:
        tuple: (targets, meta) where targets is a list of Target objects and
        meta is a Table of metadata (currently only BRICKNAME).

    """
    ## read spplate
    spplate = fitsio.FITS(spplate_name)
    plate = spplate[0].read_header()["PLATEID"]
    mjd = spplate[0].read_header()["MJD"]
    if not use_frames:
        infiles = [spplate_name]
    if use_frames:
        path = os.path.dirname(spplate_name)
        cameras = ['b1','r1','b2','r2']

        infiles = []
        nexp_tot=0
        for c in cameras:
            try:
                nexp = spplate[0].read_header()["NEXP_{}".format(c.upper())]
            except ValueError:
                print("DEBUG: spplate {} has no exposures in camera {} ".format(spplate_name,c))
                continue
            for i in range(1,nexp+1):
                nexp_tot += 1
                expid = str(nexp_tot)
                if nexp_tot<10:
                    expid = '0'+expid
                exp = path+"/spCFrame-"+spplate[0].read_header()["EXPID"+expid][:11]+".fits"
                infiles.append(exp)

    spplate.close()
    bricknames={}
    dic_spectra = {}

    for infile in infiles:
        h = fitsio.FITS(infile)
        assert plate == h[0].read_header()["PLATEID"]
        fs = h[5]["FIBERID"][:]
        if fiberid is not None:
            w = np.in1d(fs,fiberid)
            fs = fs[w]

        fl = h[0].read()
        iv = h[1].read()*(h[2].read()==0)
        wd = h[4].read()

        ## crop to lmin, lmax
        lmin = 3500.
        lmax = 10000.
        if use_frames:
            la = 10**h[3].read()
            if h[0].read_header()["CAMERAS"][0]=="b":
                lmax = 6000.
            else:
                lmin = 5500.
        else:
            coeff0 = h[0].read_header()["COEFF0"]
            coeff1 = h[0].read_header()["COEFF1"]
            la = 10**(coeff0 + coeff1*np.arange(fl.shape[1]))
            la = np.broadcast_to(la,fl.shape)

        imin = abs(la-lmin).min(axis=0).argmin()
        imax = abs(la-lmax).min(axis=0).argmin()

        la = la[:,imin:imax]
        fl = fl[:,imin:imax]
        iv = iv[:,imin:imax]
        wd = wd[:,imin:imax]

        w = wd<1e-5
        wd[w]=2.
        ii = np.arange(la.shape[1])
        di = ii-ii[:,None]
        di2 = di**2
        ndiag = int(4*np.ceil(wd.max())+1)
        nbins = wd.shape[1]

        for f in fs:
            i = (f-1)
            if use_frames:
                i = i%500
            if np.all(iv[i]==0):
                print("DEBUG: skipping plate,fid = {},{} (no data)".format(plate,f))
                continue

            t = platemjdfiber2targetid(plate, mjd, f)
            if t not in dic_spectra:
                dic_spectra[t]=[]
                brickname = '{}-{}'.format(plate,mjd)
                bricknames[t] = brickname

            ## build resolution from wdisp
            reso = np.zeros([ndiag,nbins])
            for idiag in range(ndiag):
                offset = ndiag//2-idiag
                d = np.diagonal(di2,offset=offset)
                if offset<0:
                    reso[idiag,:len(d)] = np.exp(-d/2/wd[i,:len(d)]**2)
                else:
                    reso[idiag,nbins-len(d):nbins]=np.exp(-d/2/wd[i,nbins-len(d):nbins]**2)

            R = Resolution(reso)
            ccd = sparse.spdiags(1./R.sum(axis=1).T, 0, *R.shape)
            R = (ccd*R).todia()
            dic_spectra[t].append(Spectrum(la[i], fl[i], iv[i], R, R.tocsr()))

        h.close()
        print("DEBUG: read {} ".format(infile))

    if targetids == None:
        targetids = sorted(list(dic_spectra.keys()))

    targets = []
    for targetid in targetids:
        spectra = dic_spectra[targetid]
        # Add the brickname to the meta dictionary.  The keys of this dictionary
        # will end up as extra columns in the output ZBEST HDU.
        tmeta = dict()
        tmeta["BRICKNAME"] = bricknames[targetid]
        tmeta["BRICKNAME_datatype"] = "S8"
        if len(spectra) > 0:
            targets.append(Target(targetid, spectra, coadd=coadd, meta=tmeta))
        else:
            print('ERROR: Target {} on {} has no good spectra'.format(targetid, os.path.basename(brickfiles[0])))

    #- Create a metadata table in case we might want to add other columns
    #- in the future
    assert len(bricknames.keys()) == len(targets)

    metatable = Table(names=("TARGETID", "BRICKNAME"), dtype=("i8", "S8",))
    for t in targetids:
        metatable.add_row( (t, bricknames[t]) )

    return targets, metatable