def get_slitmask(self, filename): """ Parse the slitmask data from a DEIMOS file into a :class:`pypeit.spectrographs.slitmask.SlitMask` object. Args: filename (:obj:`str`): Name of the file to read. """ # Open the file hdu = fits.open(filename) # Build the object data # - Find the index of the object IDs in the slit-object # mapping that match the object catalog mapid = hdu['SlitObjMap'].data['ObjectID'] catid = hdu['ObjectCat'].data['ObjectID'] indx = index_of_x_eq_y(mapid, catid) # - Pull out the slit ID, object ID, and object coordinates objects = np.array([ hdu['SlitObjMap'].data['dSlitId'][indx].astype(float), catid.astype(float), hdu['ObjectCat'].data['RA_OBJ'], hdu['ObjectCat'].data['DEC_OBJ'] ]).T # - Only keep the objects that are in the slit-object mapping objects = objects[mapid[indx] == catid] # Match the slit IDs in DesiSlits to those in BluSlits indx = index_of_x_eq_y(hdu['DesiSlits'].data['dSlitId'], hdu['BluSlits'].data['dSlitId'], strict=True) # Instantiate the slit mask object and return it self.slitmask = SlitMask( np.array([ hdu['BluSlits'].data['slitX1'], hdu['BluSlits'].data['slitY1'], hdu['BluSlits'].data['slitX2'], hdu['BluSlits'].data['slitY2'], hdu['BluSlits'].data['slitX3'], hdu['BluSlits'].data['slitY3'], hdu['BluSlits'].data['slitX4'], hdu['BluSlits'].data['slitY4'] ]).T.reshape(-1, 4, 2), slitid=hdu['BluSlits'].data['dSlitId'], align=hdu['DesiSlits'].data['slitTyp'][indx] == 'A', science=hdu['DesiSlits'].data['slitTyp'][indx] == 'P', onsky=np.array([ hdu['DesiSlits'].data['slitRA'][indx], hdu['DesiSlits'].data['slitDec'][indx], hdu['DesiSlits'].data['slitLen'][indx], hdu['DesiSlits'].data['slitWid'][indx], hdu['DesiSlits'].data['slitLPA'][indx] ]).T, objects=objects) return self.slitmask
def __init__(self, corners, slitid=None, align=None, science=None, onsky=None, objects=None): # TODO: Allow random input order and then fix # TODO: Is counter-clockwise order more natural (the order in # DEIMOS slitmasks is clockwise, which is why that was chosen # here) # Convert to a numpy array if it isn't already one _corners = numpy.asarray(corners) # Check the shape if _corners.shape[-1] != 2 or _corners.shape[-2] != 4: raise ValueError( 'Incorrect input shape. Must provide 4 corners with x and y for ' 'each corner.') # Assign corner attribute allowing for one slit on input # TODO: Annoyingly, numpy.atleast_3d appends a dimension at the # end instead of at the beginning, like what's done with # numpy.atleast_2d. self.corners = _corners.reshape(1, 4, 2) if _corners.ndim == 2 else _corners # Assign the slit IDs self.slitid = numpy.arange(self.corners.shape[0]) if slitid is None \ else numpy.atleast_1d(slitid) # Check the numbers match if self.slitid.size != self.corners.shape[0]: raise ValueError('Incorrect number of slit IDs provided.') if len(numpy.unique(self.slitid)) != len(self.slitid): raise ValueError('Slit IDs must be unique!') # Set the bitmask self.mask = numpy.zeros(self.nslits, dtype=self.bitmask.minimum_dtype()) if align is not None: _align = numpy.atleast_1d(align) if _align.size != self.nslits: raise ValueError( 'Alignment flags must be provided for each slit.') self.mask[_align] = self.bitmask.turn_on(self.mask[_align], 'ALIGN') if science is not None: _science = numpy.atleast_1d(science) if _science.size != self.nslits: raise ValueError( 'Science-target flags must be provided for each slit.') self.mask[_science] = self.bitmask.turn_on(self.mask[_science], 'SCIENCE') # On-sky coordinates of the slit center self.onsky = None if onsky is not None: self.onsky = numpy.atleast_2d(onsky) if self.onsky.shape != (self.nslits, 5): raise ValueError( 'Must provide sky coordinates and slit length, width, and PA ' 'for each slit.') # Expected objects in each slit self.objects = None self.slitindx = None if objects is not None: self.objects = numpy.atleast_2d(objects) if self.objects.shape[1] != 4: raise ValueError( 'Must provide the slit ID and sky coordinates for each object.' ) try: self.slitindx = index_of_x_eq_y(self.slitid, self.objects[:, 0].astype(int), strict=True) except: # Should only fault if there are slit IDs in `objects` # that are not in `slitid`. In that case, return a more # sensible error message than what index_of_x_eq_y # would provide. raise ValueError('Some slit IDs in object list not valid.') # Center coordinates self.center = numpy.mean(self.corners, axis=1) # Top and bottom (assuming the correct input order) self.top = numpy.mean(numpy.roll(self.corners, 1, axis=1)[:, 0:2, :], axis=1) self.bottom = numpy.mean(self.corners[:, 1:3, :], axis=1) # Length and width self.length = numpy.absolute( numpy.diff(self.corners[:, 0:2, 0], axis=1)).ravel() self.width = numpy.absolute(numpy.diff(self.corners[:, 1:3, 1], axis=1)).ravel() # Position angle self.pa = numpy.degrees( numpy.arctan2(numpy.diff(self.corners[:, 0:2, 1], axis=1), numpy.diff(self.corners[:, 0:2, 0], axis=1))).ravel() self.pa[self.pa < -90] += 180 self.pa[self.pa > 90] -= 180
def load_keck_deimoslris(filename:str, instr:str): """ Load up the mask design info from the header of the file provided Args: filename (str): instr (str): Name of spectrograph Allowed are keck_lris_xxx, keck_deimos Returns: [type]: [description] """ # Open the file hdu = io.fits_open(filename) # Build the object data # - Find the index of the object IDs in the slit-object # mapping that match the object catalog mapid = hdu['SlitObjMap'].data['ObjectID'] catid = hdu['ObjectCat'].data['ObjectID'] indx = index_of_x_eq_y(mapid, catid) objname = [item.strip() for item in hdu['ObjectCat'].data['OBJECT']] # - Pull out the slit ID, object ID, name, object coordinates, top and bottom distance objects = numpy.array([hdu['SlitObjMap'].data['dSlitId'][indx].astype(int), catid.astype(int), hdu['ObjectCat'].data['RA_OBJ'], hdu['ObjectCat'].data['DEC_OBJ'], objname, hdu['ObjectCat'].data['mag'], hdu['ObjectCat'].data['pBand'], hdu['SlitObjMap'].data['TopDist'][indx], hdu['SlitObjMap'].data['BotDist'][indx]]).T # - Only keep the objects that are in the slit-object mapping objects = objects[mapid[indx] == catid] # Match the slit IDs in DesiSlits to those in BluSlits indx = index_of_x_eq_y(hdu['DesiSlits'].data['dSlitId'], hdu['BluSlits'].data['dSlitId'], strict=True) # PA corresponding to positive x on detector (spatial) posx_pa = hdu['MaskDesign'].data['PA_PNT'][-1] # Insure it is positive posx_pa, _ = positive_maskpa(posx_pa) # Instantiate the slit mask object and return it try: hdu['BluSlits'].data['slitX0'] indices = numpy.arange(4) except KeyError: indices = numpy.arange(4)+1 #indices = numpy.arange(4) if instr == 'keck_deimos' else numpy.arange(4)+1 slit_list = [] for index in indices: for cdim in ['X', 'Y']: slit_list.append(hdu['BluSlits'].data[f'slit{cdim}{index}']) slitmask = SlitMask(numpy.array(slit_list).T.reshape(-1,4,2), slitid=hdu['BluSlits'].data['dSlitId'], align=hdu['DesiSlits'].data['slitTyp'][indx] == 'A', science=hdu['DesiSlits'].data['slitTyp'][indx] == 'P', onsky=numpy.array([hdu['DesiSlits'].data['slitRA'][indx], hdu['DesiSlits'].data['slitDec'][indx], hdu['DesiSlits'].data['slitLen'][indx], hdu['DesiSlits'].data['slitWid'][indx], hdu['DesiSlits'].data['slitLPA'][indx]]).T, objects=objects, #object_names=hdu['ObjectCat'].data['OBJECT'], mask_radec=(hdu['MaskDesign'].data['RA_PNT'][0], hdu['MaskDesign'].data['DEC_PNT'][0]), posx_pa=posx_pa) # Return return slitmask