def select_detectors(detnum=None, ndet=1, slitspatnum=None): """ Return the 1-indexed list of detectors to reduce. Args: detnum (:obj:`int`, :obj:`list`, optional): One or more detectors to reduce. If None, return the full list for the provided number of detectors (`ndet`). ndet (:obj:`int`, optional): The number of detectors for this instrument. Only used if `detnum is None`. Returns: list: List of detectors to be reduced """ if detnum is not None and slitspatnum is not None: msgs.error( "You cannot specify both detnum and slitspatnum. Too painful for over-writing SpecObjs" ) if detnum is None and slitspatnum is None: return np.arange(1, ndet + 1).tolist() elif detnum is not None: return np.atleast_1d(detnum).tolist() else: return slittrace.parse_slitspatnum(slitspatnum)[0].tolist()
def write_to_fits(self, subheader, outfile, overwrite=True, update_det=None, slitspatnum=None, debug=False): """ Write the set of SpecObj objects to one multi-extension FITS file Args: outfile (str): subheader (:obj:`dict`): overwrite (bool, optional): slitspatnum (:obj:`str` or :obj:`list`, optional): Restricted set of slits for reduction update_det (int or list, optional): If provided, do not clobber the existing file but only update the indicated detectors. Useful for re-running on a subset of detectors """ if os.path.isfile(outfile) and (not overwrite): msgs.warn("Outfile exists. Set overwrite=True to clobber it") return # If the file exists and update_det (and slit_spat_num) is provided, use the existing header # and load up all the other hdus so that we only over-write the ones # we are updating if os.path.isfile(outfile) and (update_det is not None or slitspatnum is not None): _specobjs = SpecObjs.from_fitsfile(outfile) mask = np.ones(_specobjs.nobj, dtype=bool) # Update_det if update_det is not None: # Pop out those with this detector (and slit if slit_spat_num is provided) for det in np.atleast_1d(update_det): mask[_specobjs.DET == det] = False elif slitspatnum is not None: # slitspatnum dets, spat_ids = slittrace.parse_slitspatnum(slitspatnum) for det, spat_id in zip(dets, spat_ids): mask[(_specobjs.DET == det) & (_specobjs.SLITID == spat_id)] = False _specobjs = _specobjs[mask] # Add in the new for sobj in self.specobjs: _specobjs.add_sobj(sobj) else: _specobjs = self.specobjs # Build up the Header header = initialize_header(primary=True) for key in subheader.keys(): header[key.upper()] = subheader[key] # Init prihdu = fits.PrimaryHDU() hdus = [prihdu] prihdu.header = header # Add class info prihdu.header['DMODCLS'] = (self.__class__.__name__, 'Datamodel class') prihdu.header['DMODVER'] = (self.version, 'Datamodel version') detector_hdus = {} nspec, ext = 0, 0 # Loop on the SpecObj objects for sobj in _specobjs: if sobj is None: continue # HDUs if debug: import pdb pdb.set_trace() shdul = sobj.to_hdu() if len(shdul) == 2: # Detector? detector_hdus[sobj['DET']] = shdul[1] shdu = [shdul[0]] elif len(shdul) == 1: # Detector? shdu = shdul else: msgs.error("Should not get here...") # Check -- If sobj had only 1 array, the BinTableHDU test will fail assert len(shdu) == 1, 'Bad data model!!' assert isinstance(shdu[0], fits.hdu.table.BinTableHDU), 'Bad data model2' #shdu[0].header['DMODCLS'] = (self.__class__.__name__, 'Datamodel class') #shdu[0].header['DMODVER'] = (self.version, 'Datamodel version') # Name shdu[0].name = sobj.NAME # Extension keywd = 'EXT{:04d}'.format(ext) prihdu.header[keywd] = sobj.NAME ext += 1 nspec += 1 # Append hdus += shdu # Deal with Detectors for key, item in detector_hdus.items(): # TODO - Add EXT to the primary header for these?? prefix = specobj.det_hdu_prefix(key) # Name if prefix not in item.name: # In case we are re-loading item.name = specobj.det_hdu_prefix(key) + item.name # Append hdus += [item] # A few more for the header prihdu.header['NSPEC'] = nspec # Code versions initialize_header(hdr=prihdu.header) # Finish hdulist = fits.HDUList(hdus) if debug: import pdb pdb.set_trace() hdulist.writeto(outfile, overwrite=overwrite) msgs.info("Wrote 1D spectra to {:s}".format(outfile)) return