Esempio n. 1
0
def test_parse_binning():
    """ Test parse binning algorithm
    """
    bin1, bin2 = parse.parse_binning('2,2')
    assert bin1 == 2
    assert bin2 == 2
    # Other input
    bin1, bin2 = parse.parse_binning((2,2))
    assert bin1 == 2
    assert bin2 == 2
Esempio n. 2
0
    def config_specific_par(self, par, scifile):

        # Templates
        if self.get_meta_value(scifile, 'dispname') == '600ZD':
            par['calibrations']['wavelengths']['method'] = 'full_template'
            par['calibrations']['wavelengths'][
                'reid_arxiv'] = 'keck_deimos_600.fits'
            par['calibrations']['wavelengths']['lamps'] += [
                'CdI', 'ZnI', 'HgI'
            ]
        elif self.get_meta_value(scifile, 'dispname') == '830G':
            par['calibrations']['wavelengths']['method'] = 'full_template'
            par['calibrations']['wavelengths'][
                'reid_arxiv'] = 'keck_deimos_830G.fits'
        elif self.get_meta_value(scifile, 'dispname') == '1200G':
            par['calibrations']['wavelengths']['method'] = 'full_template'
            par['calibrations']['wavelengths'][
                'reid_arxiv'] = 'keck_deimos_1200G.fits'

        # FWHM
        binning = parse.parse_binning(self.get_meta_value(scifile, 'binning'))
        par['calibrations']['wavelengths']['fwhm'] = 6.0 / binning[1]

        # Return
        return par
Esempio n. 3
0
    def order_platescale(self, binning=None):
        """
        Returns the plate scale in arcseconds for each order

        Parameters
        ----------
        None

        Optional Parameters
        --------------------
        binning: str

        Returns
        -------
        order_platescale: ndarray, float

        """

        # VIS has no binning, but for an instrument with binning we would do this
        binspectral, binspatial = parse.parse_binning(binning)

        # ToDO Either assume a linear trend or measure this
        # X-shooter manual says, but gives no exact numbers per order.
        # VIS: 65.9 pixels (0.167"/pix) at order 17 to 72.0 pixels (0.153"/pix) at order 30.

        # Right now I just assume a simple linear trend
        slit_vec = np.arange(self.norders)
        order_vec = self.slit2order(slit_vec)
        plate_scale = 0.153 + (order_vec - 30)*(0.153-0.167)/(30 - 17)
        return plate_scale*binspatial
Esempio n. 4
0
 def compound_meta(self, headarr, meta_key):
     if meta_key == 'binning':
         binspatial, binspec = parse.parse_binning(headarr[0]['BINNING'])
         binning = parse.binning2string(binspec, binspatial)
         return binning
     else:
         msgs.error("Not ready for this compound meta")
Esempio n. 5
0
    def compound_meta(self, headarr, meta_key):
        """
        Methods to generate metadata requiring interpretation of the header
        data, instead of simply reading the value of a header card.

        Args:
            headarr (:obj:`list`):
                List of `astropy.io.fits.Header`_ objects.
            meta_key (:obj:`str`):
                Metadata keyword to construct.

        Returns:
            object: Metadata value read from the header(s).
        """
        if meta_key == 'binning':
            # binning in the raw frames
            ccdsum = headarr[1].get('CCDSUM')
            if ccdsum is not None:
                binspatial, binspec = parse.parse_binning(ccdsum)
                binning = parse.binning2string(binspec, binspatial)
            else:
                # binning in the spec2d file
                binning = headarr[0].get('BINNING')
            if binning is None:
                msgs.error('Binning not found')
            return binning
Esempio n. 6
0
    def config_specific_par(self, scifile, inp_par=None):
        """
        Modify the ``PypeIt`` parameters to hard-wired values used for
        specific instrument configurations.

        Args:
            scifile (:obj:`str`):
                File to use when determining the configuration and how
                to adjust the input parameters.
            inp_par (:class:`~pypeit.par.parset.ParSet`, optional):
                Parameter set used for the full run of PypeIt.  If None,
                use :func:`default_pypeit_par`.

        Returns:
            :class:`~pypeit.par.parset.ParSet`: The PypeIt parameter set
            adjusted for configuration specific parameter values.
        """
        par = super().config_specific_par(scifile, inp_par=inp_par)

        headarr = self.get_headarr(scifile)

        # Turn PCA off for long slits
        if 'arcsec' in self.get_meta_value(headarr, 'decker'):
            par['calibrations']['slitedges']['sync_predict'] = 'nearest'

        # Allow for various binning
        binning = parse.parse_binning(self.get_meta_value(headarr, 'binning'))
        par['calibrations']['wavelengths']['fwhm_fromlines'] = True

        return par
Esempio n. 7
0
    def order_platescale(self, order_vec, binning=None):
        """
        Return the platescale for each echelle order.

        This routine is only defined for echelle spectrographs, and it is
        undefined in the base class.

        Args:
            order_vec (`numpy.ndarray`_):
                The vector providing the order numbers.
            binning (:obj:`str`, optional):
                The string defining the spectral and spatial binning.

        Returns:
            `numpy.ndarray`_: An array with the platescale for each order
            provided by ``order``.
        """
        binspectral, binspatial = parse.parse_binning(binning)

        # ToDO Either assume a linear trend or measure this
        # X-shooter manual says, but gives no exact numbers per order.
        # UVB: 65.9 pixels (0.167“/pix) at order 14 to 70.8 pixels (0.155”/pix) at order 24

        # Assume a simple linear trend
        plate_scale = 0.155 + (order_vec - 24) * (0.155 - 0.167) / (24 - 14)

        # Right now I just took the average
        return np.full(self.norders, 0.161) * binspatial
Esempio n. 8
0
    def order_platescale(self, order_vec, binning=None):
        """
        Return the platescale for each echelle order.

        This routine is only defined for echelle spectrographs, and it is
        undefined in the base class.

        Args:
            order_vec (`numpy.ndarray`_):
                The vector providing the order numbers.
            binning (:obj:`str`, optional):
                The string defining the spectral and spatial binning.

        Returns:
            `numpy.ndarray`_: An array with the platescale for each order
            provided by ``order``.
        """
        # VIS has no binning, but for an instrument with binning we would do this
        binspectral, binspatial = parse.parse_binning(binning)

        # ToDO Either assume a linear trend or measure this
        # X-shooter manual says, but gives no exact numbers per order.
        # VIS: 65.9 pixels (0.167"/pix) at order 17 to 72.0 pixels (0.153"/pix) at order 30.

        # Right now I just assume a simple linear trend
        plate_scale = 0.153 + (order_vec - 30) * (0.153 - 0.167) / (30 - 17)
        return plate_scale * binspatial
Esempio n. 9
0
    def order_platescale(self, binning=None):
        """
        Returns the plate scale in arcseconds for each order

        Parameters
        ----------
        None

        Optional Parameters
        --------------------
        binning: str

        Returns
        -------
        order_platescale: ndarray, float

        """
        msgs.error("REFACTOR")

        binspectral, binspatial = parse.parse_binning(binning)

        # ToDO Either assume a linear trend or measure this
        # X-shooter manual says, but gives no exact numbers per order.
        # UVB: 65.9 pixels (0.167“/pix) at order 14 to 70.8 pixels (0.155”/pix) at order 24

        # Right now I just took the average
        return np.full(self.norders, 0.161) * binspatial
Esempio n. 10
0
    def bpm(self, shape=None, filename=None, det=None, **null_kwargs):
        """
        Override parent bpm function with BPM specific to X-Shooter VIS.

        .. todo::
            Allow for binning changes.

        Parameters
        ----------
        det : int, REQUIRED
        **null_kwargs:
            Captured and never used

        Returns
        -------
        bpix : ndarray
          0 = ok; 1 = Mask

        """
        msgs.info("Custom bad pixel mask for MAGE")
        self.empty_bpm(shape=shape, filename=filename, det=det)
        # Get the binning
        hdu = fits.open(filename)
        binspatial, binspec = parse.parse_binning(hdu[0].header['BINNING'])
        hdu.close()
        # Do it
        self.bpm_img[:, :10 // binspatial] = 1.
        self.bpm_img[:, 1020 // binspatial:] = 1.
        # Return
        return self.bpm_img
Esempio n. 11
0
    def compound_meta(self, headarr, meta_key):
        """

        Args:
            headarr: list
            meta_key: str

        Returns:
            value

        """
        if meta_key == 'binning':
            binspatial, binspec = parse.parse_binning(headarr[0]['BINNING'])
            binning = parse.binning2string(binspec, binspatial)
            return binning
        elif meta_key == 'dispangle':
            if headarr[0]['GRATEPOS'] == 3:
                return headarr[0]['G3TLTWAV']
            elif headarr[0]['GRATEPOS'] == 4:
                return headarr[0]['G4TLTWAV']
            else:
                msgs.warn(
                    'This is probably a problem. Non-standard DEIMOS GRATEPOS={0}.'
                    .format(headarr[0]['GRATEPOS']))
        else:
            msgs.error("Not ready for this compound meta")
Esempio n. 12
0
    def wavegrid(self, binning=None, midpoint=False, samp_fact=1.0):
        r"""
        Construct a fixed wavelength grid in :math:`\log_{10} \lambda`. This
        method is mostly used for echelle spectrographs.

        This is primarily a wrapper for
        :func:`pypeit.core.wavecal.wvutils.wavegrid`.

        Args:
            binning (:obj:`str`, optional):
                String representation of the spectral and spatial binning. If
                None, assumed to be ``'1,1'``.
            midpoint (:obj:`bool`, optional):
                Increment the grid to the spectral mid-point.
            samp_fact (:obj:`float`, optional):

                The pixel-sampling factor. If 1., the spectra are sampled by
                the logarithmic step associated with a single binned pixel
                (:attr:`dloglam`).

        Returns:
            `numpy.ndarray`_: The logarithmically sampled wavelength grid;
            grid points are in wavelength, *not* ``log10(wavelength)``.
        """
        binspectral, binspatial = parse.parse_binning(binning)
        logmin, logmax = self.loglam_minmax
        loglam_grid = wvutils.wavegrid(logmin,
                                       logmax,
                                       self.dloglam * binspectral,
                                       samp_fact=samp_fact)
        if midpoint:
            loglam_grid = loglam_grid + self.dloglam * binspectral / samp_fact / 2.0

        return np.power(10.0, loglam_grid)
Esempio n. 13
0
    def get_wv_calib(self):
        """
        Load or generate the 1D wavelength calibrations

        Requirements:
          msarc, msbpm, slits, det, par

        Returns:
            dict: :attr:`wv_calib` calibration dict and the updated slit mask array
        """
        # Check for existing data
        if not self._chk_objs(['msarc', 'msbpm', 'slits']):
            msgs.warn(
                'Not enough information to load/generate the wavelength calibration. Skipping and may crash down the line'
            )
            return None

        # Check internals
        self._chk_set(['det', 'calib_ID', 'par'])
        if 'arc' not in self.master_key_dict.keys():
            msgs.error('Arc master key not set.  First run get_arc.')

        # No wavelength calibration requested
        if self.par['wavelengths']['reference'] == 'pixel':
            msgs.info("A wavelength calibration will not be performed")
            self.wv_calib = None
            return self.wv_calib

        # Grab arc binning (may be different from science!)
        # TODO : Do this internally when we have a wv_calib DataContainer
        binspec, binspat = parse.parse_binning(self.msarc.detector.binning)

        # Instantiate
        self.waveCalib = wavecalib.WaveCalib(
            self.msarc,
            self.slits,
            self.spectrograph,
            self.par['wavelengths'],
            binspectral=binspec,
            det=self.det,
            master_key=self.master_key_dict['arc'],  # For QA naming
            qa_path=self.qa_path,
            msbpm=self.msbpm)
        # Load from disk (MasterFrame)?
        masterframe_name = masterframe.construct_file_name(
            wavecalib.WaveCalib,
            self.master_key_dict['arc'],
            master_dir=self.master_dir)
        if os.path.isfile(masterframe_name) and self.reuse_masters:
            # Load from disk
            self.wv_calib = self.waveCalib.load(masterframe_name)
            self.slits.mask_wvcalib(self.wv_calib)
        else:
            self.wv_calib = self.waveCalib.run(skip_QA=(not self.write_qa))
            # Save to Masters
            self.waveCalib.save(outfile=masterframe_name)

        # Return
        return self.wv_calib
Esempio n. 14
0
    def config_specific_par(self, scifile, inp_par=None):
        """
        Modify the PypeIt parameters to hard-wired values used for
        specific instrument configurations.

        .. todo::
            Document the changes made!

        Args:
            scifile (str):
                File to use when determining the configuration and how
                to adjust the input parameters.
            inp_par (:class:`pypeit.par.parset.ParSet`, optional):
                Parameter set used for the full run of PypeIt.  If None,
                use :func:`default_pypeit_par`.

        Returns:
            :class:`pypeit.par.parset.ParSet`: The PypeIt paramter set
            adjusted for configuration specific parameter values.
        """
        # Start with instrument wide
        par = super(KeckLRISRSpectrograph,
                    self).config_specific_par(scifile, inp_par=inp_par)

        # Lacosmic CR settings
        #   Grab the defaults for LRISr
        binning = self.get_meta_value(scifile, 'binning')
        # Unbinned LRISr needs very aggressive LACosmics parameters for 1x1 binning
        if binning == '1,1':
            sigclip = 3.0
            objlim = 0.5
            par['scienceframe']['process']['sigclip'] = sigclip
            par['scienceframe']['process']['objlim'] = objlim

        # Wavelength calibrations
        if self.get_meta_value(
                scifile,
                'dispname') == '400/8500':  # This is basically a reidentify
            par['calibrations']['wavelengths'][
                'reid_arxiv'] = 'keck_lris_red_400.fits'
            par['calibrations']['wavelengths']['method'] = 'full_template'
            par['calibrations']['wavelengths']['sigdetect'] = 20.0
            par['calibrations']['wavelengths']['nsnippet'] = 1
        elif self.get_meta_value(scifile, 'dispname') == '600/5000':
            par['calibrations']['wavelengths'][
                'reid_arxiv'] = 'keck_lris_red_600_5000.fits'
            par['calibrations']['wavelengths']['method'] = 'full_template'
        elif self.get_meta_value(scifile, 'dispname') == '1200/9000':
            par['calibrations']['wavelengths'][
                'reid_arxiv'] = 'keck_lris_red_1200_9000.fits'
            par['calibrations']['wavelengths']['method'] = 'full_template'

        # FWHM
        binning = parse.parse_binning(self.get_meta_value(scifile, 'binning'))
        par['calibrations']['wavelengths']['fwhm'] = 8.0 / binning[0]

        # Return
        return par
Esempio n. 15
0
    def config_specific_par(self, scifile, inp_par=None):
        """
        Modify the PypeIt parameters to hard-wired values used for
        specific instrument configurations.

        .. todo::
            Document the changes made!
        
        Args:
            scifile (str):
                File to use when determining the configuration and how
                to adjust the input parameters.
            inp_par (:class:`pypeit.par.parset.ParSet`, optional):
                Parameter set used for the full run of PypeIt.  If None,
                use :func:`default_pypeit_par`.

        Returns:
            :class:`pypeit.par.parset.ParSet`: The PypeIt paramter set
            adjusted for configuration specific parameter values.
        """
        par = self.default_pypeit_par() if inp_par is None else inp_par

        headarr = self.get_headarr(scifile)

        # Turn PCA off for long slits
        # TODO: I'm a bit worried that this won't catch all
        # long-slits...
        if ('Long' in self.get_meta_value(
                headarr, 'decker')) or ('LVMslit' in self.get_meta_value(
                    headarr, 'decker')):
            par['calibrations']['slitedges']['sync_predict'] = 'nearest'

        # Templates
        if self.get_meta_value(headarr, 'dispname') == '600ZD':
            par['calibrations']['wavelengths']['method'] = 'full_template'
            par['calibrations']['wavelengths'][
                'reid_arxiv'] = 'keck_deimos_600.fits'
            par['calibrations']['wavelengths']['lamps'] += [
                'CdI', 'ZnI', 'HgI'
            ]
        elif self.get_meta_value(headarr, 'dispname') == '830G':
            par['calibrations']['wavelengths']['method'] = 'full_template'
            par['calibrations']['wavelengths'][
                'reid_arxiv'] = 'keck_deimos_830G.fits'
        elif self.get_meta_value(headarr, 'dispname') == '1200G':
            par['calibrations']['wavelengths']['method'] = 'full_template'
            par['calibrations']['wavelengths'][
                'reid_arxiv'] = 'keck_deimos_1200G.fits'

        # FWHM
        binning = parse.parse_binning(self.get_meta_value(headarr, 'binning'))
        par['calibrations']['wavelengths']['fwhm'] = 6.0 / binning[1]

        # Return
        return par
Esempio n. 16
0
    def config_specific_par(self, scifile, inp_par=None):
        """
        Modify the PypeIt parameters to hard-wired values used for
        specific instrument configurations.

        .. todo::
            Document the changes made!

        Args:
            scifile (str):
                File to use when determining the configuration and how
                to adjust the input parameters.
            inp_par (:class:`pypeit.par.parset.ParSet`, optional):
                Parameter set used for the full run of PypeIt.  If None,
                use :func:`default_pypeit_par`.

        Returns:
            :class:`pypeit.par.parset.ParSet`: The PypeIt paramter set
            adjusted for configuration specific parameter values.
        """
        par = self.default_pypeit_par() if inp_par is None else inp_par
        # TODO: Should we allow the user to override these?

        # Wavelength calibrations
        if self.get_meta_value(scifile, 'dispname') == '300/5000':
            par['calibrations']['wavelengths']['reid_arxiv'] = 'keck_lris_blue_300_d680.fits'
            par['flexure']['spectrum'] = os.path.join(resource_filename('pypeit', 'data/sky_spec/'),
                                                      'sky_LRISb_400.fits')
        elif self.get_meta_value(scifile, 'dispname') == '400/3400':
            par['calibrations']['wavelengths']['reid_arxiv'] = 'keck_lris_blue_400_d560.fits'
            par['flexure']['spectrum'] = os.path.join(resource_filename('pypeit', 'data/sky_spec/'),
                                                  'sky_LRISb_400.fits')
        elif self.get_meta_value(scifile, 'dispname') == '600/4000':
            par['calibrations']['wavelengths']['reid_arxiv'] = 'keck_lris_blue_600_d560.fits'
            par['flexure']['spectrum'] = os.path.join(resource_filename('pypeit', 'data/sky_spec/'),
                                                      'sky_LRISb_600.fits')
        elif self.get_meta_value(scifile, 'dispname') == '1200/3400':
            par['calibrations']['wavelengths']['reid_arxiv'] = 'keck_lris_blue_1200_d460.fits'
            par['flexure']['spectrum'] = os.path.join(resource_filename('pypeit', 'data/sky_spec/'),
                                                      'sky_LRISb_600.fits')

        # FWHM
        binning = parse.parse_binning(self.get_meta_value(scifile, 'binning'))
        par['calibrations']['wavelengths']['fwhm'] = 8.0 / binning[0]

        # Slit tracing
        # Reduce the slit parameters because the flux does not span the full detector
        #   It is primarily on the upper half of the detector (usually)
        if self.get_meta_value(scifile, 'dispname') == '300/5000':
            par['calibrations']['slits']['mask_frac_thresh'] = 0.45
            par['calibrations']['slits']['smash_range'] = [0.5, 1.]

        # Return
        return par
Esempio n. 17
0
    def _fill_tslits_dict(self):
        """
        Build a simple dictionary holding the key trace bits and pieces that PypeIt wants

        Returns:
            dict: Trace slits dict

        """
        self.tslits_dict = {}

        # Have the slit boundaries been tweaked? If so use the tweaked
        # boundaries.  TODO: Have the dict keys have the same name as
        # the attribute
        self.tslits_dict['slit_left_orig'] = self.slit_left
        self.tslits_dict['slit_righ_orig'] = self.slit_righ

        if self.slit_left_tweak is not None:
            self.tslits_dict['slit_left_tweak'] = self.slit_left_tweak
            self.tslits_dict['slit_righ_tweak'] = self.slit_righ_tweak

            self.tslits_dict['slit_left'] = self.slit_left_tweak
            self.tslits_dict['slit_righ'] = self.slit_righ_tweak
        else:
            self.tslits_dict['slit_left'] = self.slit_left
            self.tslits_dict['slit_righ'] = self.slit_righ

        # Fill in the rest of the keys that were generated by
        # make_pixel_arrays from the slit boundaries. This was done with
        # tweaked boundaries if they exist.  TODO: Some of these
        # quantities may be deprecated.

        #for key in ['slitcen', 'pixwid', 'lordpix','rordpix', 'extrapord']:
        #    self.tslits_dict[key] = getattr(self, key)
        # add in the image size and some stuff to create the slitmask

        self.tslits_dict['maskslits'] = self.maskslits
        self.tslits_dict['slitcen'] = self.slitcen
        self.tslits_dict['nspec'] = self.mstrace.shape[0]
        self.tslits_dict['nspat'] = self.mstrace.shape[1]
        self.tslits_dict['nslits'] = self.slit_left.shape[1]
        self.tslits_dict['pad'] = self.par['pad']
        binspectral, binspatial = parse.parse_binning(self.binning)
        self.tslits_dict['binspectral'] = binspectral
        self.tslits_dict['binspatial'] = binspatial
        self.tslits_dict['spectrograph'] = self.spectrograph.spectrograph
        slit_spat_pos = trace_slits.slit_spat_pos(self.tslits_dict)
        spec_min_max = self.spectrograph.slit_minmax(slit_spat_pos, binspectral = binspectral)
        self.tslits_dict['spec_min'], self.tslits_dict['spec_max'] = spec_min_max[0, :], spec_min_max[1, :]
        # Now extrapolate the traces JFH turning this off for now.
        #self.tslits_dict['slit_left'] = trace_slits.extrapolate_trace(self.tslits_dict['slit_left'], spec_min_max)
        #self.tslits_dict['slit_righ'] = trace_slits.extrapolate_trace(self.tslits_dict['slit_righ'], spec_min_max)

        return self.tslits_dict
Esempio n. 18
0
    def config_specific_par(self, par, scifile):
        """
        Set par values according to the specific frame

        Args:
            par:  ParSet
            scifile: str
              Name of the science file to use

        Returns:
            par

        """
        # Wavelength calibrations
        if self.get_meta_value(scifile, 'dispname') == '300/5000':
            par['calibrations']['wavelengths'][
                'reid_arxiv'] = 'keck_lris_blue_300_d680.fits'
            par['flexure']['spectrum'] = os.path.join(
                resource_filename('pypeit', 'data/sky_spec/'),
                'sky_LRISb_400.fits')
        elif self.get_meta_value(scifile, 'dispname') == '400/3400':
            par['calibrations']['wavelengths'][
                'reid_arxiv'] = 'keck_lris_blue_400_d560.fits'
            par['flexure']['spectrum'] = os.path.join(
                resource_filename('pypeit', 'data/sky_spec/'),
                'sky_LRISb_400.fits')
        elif self.get_meta_value(scifile, 'dispname') == '600/4000':
            par['calibrations']['wavelengths'][
                'reid_arxiv'] = 'keck_lris_blue_600_d560.fits'
            par['flexure']['spectrum'] = os.path.join(
                resource_filename('pypeit', 'data/sky_spec/'),
                'sky_LRISb_600.fits')
        elif self.get_meta_value(scifile, 'dispname') == '1200/3400':
            par['calibrations']['wavelengths'][
                'reid_arxiv'] = 'keck_lris_blue_1200_d460.fits'
            par['flexure']['spectrum'] = os.path.join(
                resource_filename('pypeit', 'data/sky_spec/'),
                'sky_LRISb_600.fits')

        # FWHM
        binning = parse.parse_binning(self.get_meta_value(scifile, 'binning'))
        par['calibrations']['wavelengths']['fwhm'] = 8.0 / binning[0]

        # Slit tracing
        # Reduce the slit parameters because the flux does not span the full detector
        #   It is primarily on the upper half of the detector (usually)
        if self.get_meta_value(scifile, 'dispname') == '300/5000':
            par['calibrations']['slits']['mask_frac_thresh'] = 0.45
            par['calibrations']['slits']['smash_range'] = [0.5, 1.]

        # Return
        return par
Esempio n. 19
0
    def slitmask(self, tslits_dict, pad=None):
        """
         Generic routine ton construct a slitmask image from a tslits_dict. Children of this class can
         overload this function to implement instrument specific slitmask behavior, for example setting
         where the orders on an echelle spectrograph end

         Parameters
         -----------
         tslits_dict: dict
            Trace slits dictionary with slit boundary information

         Optional Parameters
         pad: int or float
            Padding of the slit boundaries
         binning: tuple
            Spectrograph binning in spectral and spatial directions

         Returns
         -------
         slitmask: ndarray int
            Image with -1 where there are no slits/orders, and an integer where there are slits/order with the integer
            indicating the slit number going from 0 to nslit-1 from left to right.

         """

        # These lines are always the same
        pad = tslits_dict['pad'] if pad is None else pad
        nslits = tslits_dict['lcen'].shape[1]
        if nslits != self.norders:
            msgs.error('Not all the orders were identified!')

        slitmask = pixels.slit_pixels(tslits_dict['lcen'],
                                      tslits_dict['rcen'],
                                      tslits_dict['nspat'],
                                      pad=pad)
        spec_img = np.outer(
            np.arange(tslits_dict['nspec'], dtype=int),
            np.ones(tslits_dict['nspat'],
                    dtype=int))  # spectral position everywhere along image

        binning = tslits_dict['binning']
        binspectral, binspatial = parse.parse_binning(binning)
        # These are the order boundaries determined by eye by JFH.
        order_max = np.asarray([4000] * 14 + [3000]) // binspectral
        order_min = np.asarray([2000, 1000] + [0] * 13) // binspectral
        # TODO add binning adjustments to these
        for iorder in range(self.norders):
            orderbad = (slitmask == iorder) & ((spec_img < order_min[iorder]) |
                                               (spec_img > order_max[iorder]))
            slitmask[orderbad] = -1

        return slitmask
Esempio n. 20
0
    def compound_meta(self, headarr, meta_key):
        """

        Args:
            headarr: list
            meta_key: str

        Returns:
            value

        """
        if meta_key == 'binning':
            binspatial, binspec = parse.parse_binning(headarr[0]['BINNING'])
            return parse.binning2string(binspec, binspatial)
Esempio n. 21
0
    def compound_meta(self, headarr, meta_key):
        """
        Methods to generate metadata requiring interpretation of the header
        data, instead of simply reading the value of a header card.

        Args:
            headarr (:obj:`list`):
                List of `astropy.io.fits.Header`_ objects.
            meta_key (:obj:`str`):
                Metadata keyword to construct.

        Returns:
            object: Metadata value read from the header(s).
        """
        if meta_key == 'binning':
            binspatial, binspec = parse.parse_binning(headarr[0]['BINNING'])
            binning = parse.binning2string(binspec, binspatial)
            return binning
        elif meta_key == 'slitwid':
            # Get the slice scale
            slicescale = 0.00037718  # Degrees per 'large slicer' slice
            ifunum = headarr[0]['IFUNUM']
            if ifunum == 2:
                slicescale /= 2.0
            elif ifunum == 3:
                slicescale /= 4.0
            return slicescale
        elif meta_key == 'ra' or meta_key == 'dec':
            try:
                if self.is_nasmask(headarr[0]):
                    hdrstr = 'RABASE' if meta_key == 'ra' else 'DECBASE'
                else:
                    hdrstr = 'RA' if meta_key == 'ra' else 'DEC'
            except KeyError:
                try:
                    hdrstr = 'TARGRA' if meta_key == 'ra' else 'TARGDEC'
                except KeyError:
                    hdrstr = ''
            return headarr[0][hdrstr]
        elif meta_key == 'pressure':
            return headarr[0]['WXPRESS'] * 0.001 * units.bar
        elif meta_key == 'temperature':
            return headarr[0]['WXOUTTMP'] * units.deg_C
        elif meta_key == 'humidity':
            return headarr[0]['WXOUTHUM'] / 100.0
        elif meta_key == 'obstime':
            return Time(headarr[0]['DATE-END'])
        else:
            msgs.error("Not ready for this compound meta")
Esempio n. 22
0
    def order_platescale(self, order_vec, binning=None):
        """
        Returns the plate scale in arcseconds for each order

        Args:
            order_vec (np.ndarray): Order numbers
            binning (optional):

        Returns:
            np.ndarray: Platescale

        """
        norders = len(order_vec)
        binspatial, binspec = parse.parse_binning(binning)
        return np.full(norders, 0.30 * binspatial)
Esempio n. 23
0
    def compound_meta(self, headarr, meta_key):
        """

        Args:
            headarr: list
            meta_key: str

        Returns:
            value

        """
        if meta_key == 'binning':
            binspatial, binspec = parse.parse_binning(np.array([headarr[0]['CCDXBIN'], headarr[0]['CCDYBIN']]))
            binning = parse.binning2string(binspatial, binspec)
            return binning
        msgs.error("Not ready for this compound meta")
Esempio n. 24
0
    def config_specific_par(self, par, scifile):
        """
        Set par values according to the specific frame

        Args:
            par:  ParSet
            scifile: str
              Name of the science file to use

        Returns:
            par

        """
        # Lacosmic CR settings
        #   Grab the defaults for LRISr
        binning = self.get_meta_value(scifile, 'binning')
        # Unbinned LRISr needs very aggressive LACosmics parameters for 1x1 binning
        if binning == '1,1':
            sigclip = 3.0
            objlim = 0.5
            par['scienceframe']['process']['sigclip'] = sigclip
            par['scienceframe']['process']['objlim'] = objlim

        # Wavelength calibrations
        if self.get_meta_value(
                scifile,
                'dispname') == '400/8500':  # This is basically a reidentify
            par['calibrations']['wavelengths'][
                'reid_arxiv'] = 'keck_lris_red_400.fits'
            par['calibrations']['wavelengths']['method'] = 'full_template'
            par['calibrations']['wavelengths']['sigdetect'] = 20.0
            par['calibrations']['wavelengths']['nsnippet'] = 1
        elif self.get_meta_value(scifile, 'dispname') == '600/5000':
            par['calibrations']['wavelengths'][
                'reid_arxiv'] = 'keck_lris_red_600_5000.fits'
            par['calibrations']['wavelengths']['method'] = 'full_template'
        elif self.get_meta_value(scifile, 'dispname') == '1200/9000':
            par['calibrations']['wavelengths'][
                'reid_arxiv'] = 'keck_lris_red_1200_9000.fits'
            par['calibrations']['wavelengths']['method'] = 'full_template'

        # FWHM
        binning = parse.parse_binning(self.get_meta_value(scifile, 'binning'))
        par['calibrations']['wavelengths']['fwhm'] = 8.0 / binning[0]

        # Return
        return par
Esempio n. 25
0
    def config_specific_par(self, scifile, inp_par=None):
        """
        Modify the PypeIt parameters to hard-wired values used for
        specific instrument configurations.

        .. todo::
            Document the changes made!
        
        Args:
            scifile (str):
                File to use when determining the configuration and how
                to adjust the input parameters.
            inp_par (:class:`pypeit.par.parset.ParSet`, optional):
                Parameter set used for the full run of PypeIt.  If None,
                use :func:`default_pypeit_par`.

        Returns:
            :class:`pypeit.par.parset.ParSet`: The PypeIt paramter set
            adjusted for configuration specific parameter values.
        """
        par = self.default_pypeit_par() if inp_par is None else inp_par
        # TODO: Should we allow the user to override these?

        # Templates
        if self.get_meta_value(scifile, 'dispname') == '600ZD':
            par['calibrations']['wavelengths']['method'] = 'full_template'
            par['calibrations']['wavelengths'][
                'reid_arxiv'] = 'keck_deimos_600.fits'
            par['calibrations']['wavelengths']['lamps'] += [
                'CdI', 'ZnI', 'HgI'
            ]
        elif self.get_meta_value(scifile, 'dispname') == '830G':
            par['calibrations']['wavelengths']['method'] = 'full_template'
            par['calibrations']['wavelengths'][
                'reid_arxiv'] = 'keck_deimos_830G.fits'
        elif self.get_meta_value(scifile, 'dispname') == '1200G':
            par['calibrations']['wavelengths']['method'] = 'full_template'
            par['calibrations']['wavelengths'][
                'reid_arxiv'] = 'keck_deimos_1200G.fits'

        # FWHM
        binning = parse.parse_binning(self.get_meta_value(scifile, 'binning'))
        par['calibrations']['wavelengths']['fwhm'] = 6.0 / binning[1]

        # Return
        return par
Esempio n. 26
0
    def compound_meta(self, headarr, meta_key):
        """
        Methods to generate metadata requiring interpretation of the header
        data, instead of simply reading the value of a header card.

        Args:
            headarr (:obj:`list`):
                List of `astropy.io.fits.Header`_ objects.
            meta_key (:obj:`str`):
                Metadata keyword to construct.

        Returns:
            object: Metadata value read from the header(s).
        """
        if meta_key == 'binning':
            binspatial, binspec = parse.parse_binning(headarr[0]['CCDSUM'])
            binning = parse.binning2string(binspec, binspatial)
            return binning
Esempio n. 27
0
    def compound_meta(self, headarr, meta_key):
        """

        Args:
            headarr: list
            meta_key: str

        Returns:
            value

        """
        if meta_key == 'binning':
            binspatial, binspec = parse.parse_binning(headarr[0]['BINNING'])
            return parse.binning2string(binspec, binspatial)
        elif meta_key == 'mjd':
            time = '{:s}T{:s}'.format(headarr[0]['UT-DATE'], headarr[0]['UT-TIME'])
            ttime = Time(time, format='isot')
            return ttime.mjd
        else:
            msgs.error("Not ready for this compound meta")
Esempio n. 28
0
    def order_platescale(self, order_vec, binning=None):
        """
        Return the platescale for each echelle order.

        This routine is only defined for echelle spectrographs, and it is
        undefined in the base class.

        Args:
            order_vec (`numpy.ndarray`_):
                The vector providing the order numbers.
            binning (:obj:`str`, optional):
                The string defining the spectral and spatial binning.

        Returns:
            `numpy.ndarray`_: An array with the platescale for each order
            provided by ``order``.
        """
        norders = len(order_vec)
        binspatial, binspec = parse.parse_binning(binning)
        return np.full(norders, 0.30 * binspatial)
Esempio n. 29
0
    def wavegrid(self, binning=None, midpoint=False,samp_fact=1.0):
        """
        Routine to generate a fixed wavelength grid in log_10 lambda. Mostly used by echelle spectrographs

        Args:
            binning:
            midpoint:
            samp_fact:

        Returns:

        """

        binspectral, binspatial = parse.parse_binning(binning)
        logmin, logmax = self.loglam_minmax
        loglam_grid = wvutils.wavegrid(logmin, logmax, self.dloglam*binspectral, samp_fact=samp_fact)
        if midpoint:
            loglam_grid = loglam_grid + self.dloglam*binspectral/samp_fact/2.0

        return np.power(10.0,loglam_grid)
Esempio n. 30
0
    def bpm(self, filename, det, shape=None, msbias=None):
        """
        Generate a default bad-pixel mask.

        Even though they are both optional, either the precise shape for
        the image (``shape``) or an example file that can be read to get
        the shape (``filename`` using :func:`get_image_shape`) *must* be
        provided.

        Args:
            filename (:obj:`str` or None):
                An example file to use to get the image shape.
            det (:obj:`int`):
                1-indexed detector number to use when getting the image
                shape from the example file.
            shape (tuple, optional):
                Processed image shape
                Required if filename is None
                Ignored if filename is not None
            msbias (`numpy.ndarray`_, optional):
                Master bias frame used to identify bad pixels

        Returns:
            `numpy.ndarray`_: An integer array with a masked value set
            to 1 and an unmasked value set to 0.  All values are set to
            0.
        """
        # Call the base-class method to generate the empty bpm
        bpm_img = super().bpm(filename, det, shape=shape, msbias=msbias)

        # Get the binning
        msgs.info("Custom bad pixel mask for MAGE")
        hdu = io.fits_open(filename)
        binspatial, binspec = parse.parse_binning(hdu[0].header['BINNING'])
        hdu.close()
        # Do it
        bpm_img[:, :10 //
                binspatial] = 1.  # Setting BPM on the edge of the detector often leads to false edges
        bpm_img[:, 1020 // binspatial:] = 1.
        # Return
        return bpm_img