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