Example #1
0
 def test_from_mag_unit_error(self):
     bp = synphot.SpectralElement(synphot.Box1D,
                                  x_0=11.7 * u.um,
                                  width=0.1 * u.um)
     with pytest.raises(ValueError):
         Efrho.from_mag(5, 'asdf', 1 * u.arcsec, bp,
                        dict(rh=1.5 * u.au, delta=1.0 * u.au))
Example #2
0
 def test_from_mag_bandpass(self, unit, efrho0):
     aper = 1 * u.arcsec
     # width = 0.1 um for speed
     bp = synphot.SpectralElement(synphot.Box1D,
                                  x_0=11.7 * u.um,
                                  width=0.1 * u.um)
     eph = dict(rh=1.0 * u.au, delta=1.0 * u.au)
     Tscale = 1.1
     efrho = Efrho.from_mag(5, unit, aper, eph, bandpass=bp, Tscale=Tscale)
     assert np.isclose(efrho.cm, efrho0, rtol=0.001)
Example #3
0
    def test_observe_bandpass(self):
        w = u.Quantity(np.linspace(0.3, 1.0), 'um')
        f = u.Quantity(np.ones(len(w)), 'W/(m2 um)')
        s = Star.from_array(w, f)

        bp = synphot.SpectralElement(synphot.Box1D,
                                     x_0=0.55 * u.um,
                                     width=0.1 * u.um)
        fluxd = s.observe(bp)
        assert np.allclose(fluxd.value, [1])

        bps = [
            synphot.SpectralElement(synphot.Box1D,
                                    x_0=0.55 * u.um,
                                    width=0.1 * u.um),
            synphot.SpectralElement(synphot.Box1D,
                                    x_0=0.65 * u.um,
                                    width=0.1 * u.um)
        ]
        fluxd = s.observe(bps, unit='W/(m2 um)')
        assert np.allclose(fluxd.value, [1, 1])
Example #4
0
    def __call__(self, wave_or_freq, unit=None):
        """Evaluate the source spectrum.

        Parameters
        ----------
        wave_or_freq : `~astropy.units.Quantity`
          Requested wavelength or frequencies of the resulting
          spectrum.  If an array, `wave_or_freq` specifies bin
          centers.  If a single value, fluxd will be interpolated to
          this wavelength/frequency.

        unit : string, `~astropy.units.Unit`, optional
          Spectral units of the output: flux density, 'vegamag',
          'ABmag', or 'STmag'.  If ``None``, return units are W/(m2
          μm) for ``wave_or_freq`` as wavelength, otherwise return Jy.

        Returns
        -------
        fluxd : `~astropy.units.Quantity`
          The spectrum binned to match `wave_or_freq`.  If a single
          point is requested, the original spectrum is interpolated to
          it.

        """

        import numpy as np
        import synphot

        if unit is None:
            if wave_or_freq.unit.is_equivalent('m'):
                unit = u.Unit('W/(m2 um)')
            else:
                unit = u.Jy

        if np.size(wave_or_freq) > 1:
            # Method adapted from http://www.astrobetter.com/blog/2013/08/12/python-tip-re-sampling-spectra-with-pysynphot/
            specele = synphot.SpectralElement(synphot.ConstFlux1D(1))
            obs = synphot.Observation(self.source,
                                      specele,
                                      binset=wave_or_freq,
                                      force='taper')

            # The following is the same as obs.binflux, except sample_binned
            # will do the unit coversions.
            fluxd = obs.sample_binned(flux_unit=unit)
        else:
            fluxd = self.source(wave_or_freq, unit)

        return fluxd
Example #5
0
    def test_mag(self):
        # compare to sbpy
        g = {'rh': 2.0 * u.au, 'delta': 1.0 * u.au, 'phase': 0 * u.deg}
        afrho = Afrho(100 * 2**-2, 'cm')
        tab = np.loadtxt(os.path.join(__path__[0], 'lsst-total-r.dat')).T
        r = synphot.SpectralElement(synphot.Empirical1D,
                                    points=tab[0] * u.nm,
                                    lookup_table=tab[1])
        rap = 1 * u.arcsec
        m0 = afrho.to_fluxd(r, rap, g, unit=u.ABmag).value

        comet = Comet(R=1, afrho1=100, k=-2)
        m = comet.mag(g, 'r', rap=rap.value, nucleus=False)

        assert np.isclose(m, m0, atol=0.05)
Example #6
0
 def test_mag_fluxd0_bandpass(self):
     # comapre with test_mag_bandpass
     aper = 1 * u.arcsec
     # width = 0.1 um for speed
     bp = synphot.SpectralElement(synphot.Box1D,
                                  x_0=11.7 * u.um,
                                  width=0.1 * u.um)
     eph = dict(rh=1.0 * u.au, delta=1.0 * u.au)
     Tscale = 1.1
     fluxd0 = u.Quantity(3631, 'Jy')
     efrho = Efrho(78750, 'cm')
     mag = efrho.mag(None,
                     aper,
                     eph,
                     bandpass=bp,
                     fluxd0=fluxd0,
                     Tscale=Tscale)
     assert np.isclose(mag, 5, rtol=0.001)
Example #7
0
    def observe(self, wfb, unit=None, **kwargs):
        """Observe source as through filters or spectrometer.


        Parameters
        ----------
        wfb : `~astropy.units.Quantity`, `~synphot.SpectralElement`
            Wavelengths, frequencies, or bandpasses.  May also be a
            list of ``SpectralElement``s.

        unit : string, `~astropy.units.Unit`, optional
            Spectral units of the output (flux density).  If ``None``,
            the default depends on ``wfb``: W/(m2 μm) for wavelengths
            or bandpasses, Jy for frequencies.

        **kwargs
            Additional keyword arguments for
            `~synphot.observation.Observation`, e.g., ``force``.


        Returns
        -------
        fluxd : `~astropy.units.Quantity`
            The spectrum rebinned.

        Raises
        ------
        SinglePointSpectrumError - If requested wavelengths or
            frequencies has only one value.

        Notes
        -----
        Method adapted from AstroBetter post by Jessica Lu:
        http://www.astrobetter.com/blog/2013/08/12/python-tip-re-sampling-spectra-with-pysynphot/

        """

        import synphot
        from .. import units as sbu  # avoid circular dependency

        # promote single bandpasses to a list, but preserve number of
        # dimensions
        if isinstance(wfb, (synphot.SpectralElement, str)):
            ndim = 0
            wfb = [wfb]
        else:
            ndim = np.ndim(wfb)

        if isinstance(wfb, (tuple, list)):
            if unit is None:
                unit = u.Unit('W/(m2 um)')
            else:
                unit = u.Unit(unit)

            fluxd = np.ones(len(wfb)) * unit
            for i in range(len(wfb)):
                fluxd[i] = self.filt(wfb[i], unit=unit, **kwargs)[1]
        else:
            if np.size(wfb) == 1:
                raise SinglePointSpectrumError(
                    'Multiple wavelengths or frequencies required for '
                    'observe.  Consider interpolation with {}() instead.'.
                    format(self.__class__.__name__))

            if unit is None:
                if wfb.unit.is_equivalent('m'):
                    unit = u.Unit('W/(m2 um)')
                else:
                    unit = u.Jy
            else:
                unit = u.Unit(unit)

            specele = synphot.SpectralElement(synphot.ConstFlux1D(1))

            # Use force='taper' to prevent PartialOverlap execption.
            # Specele is defined over all wavelengths, but most
            # spectral standards are not.
            kwargs['force'] = kwargs.get('force', 'taper')

            obs = synphot.Observation(self.source,
                                      specele,
                                      binset=wfb,
                                      **kwargs)

            if unit.is_equivalent(sbu.VEGAmag):
                fluxd = obs.sample_binned(flux_unit='W/(m2 um)').to(
                    unit, sbu.spectral_density_vega(wfb))
            else:
                fluxd = obs.sample_binned(flux_unit=unit)

        if np.ndim(fluxd) != ndim:
            # likely need a squeeze
            fluxd = fluxd.squeeze()

        return fluxd
Example #8
0
def box(center, width):
    return synphot.SpectralElement(
        synphot.Box1D, x_0=center * u.um, width=width * u.um)
Example #9
0
    def observe_spectrum(self, wave_or_freq, unit=None, **kwargs):
        """Observe source as through a spectrometer.

        .. Important:: This method works best when the requested
           spectral resolution is lower than the spectral resolution
           of the internal data.  If the requested
           wavelengths/frequencies are exactly the same as the
           internal spectrum, then the internal spectrum will be
           returned without binning.  This special case does not work
           for subsets of the wavelengths.


        Parameters
        ----------
        wave_or_freq : `~astropy.units.Quantity`
            Wavelengths or frequencies of the spectrum.  Spectral bins
            will be centered at these values.  The length must be
            larger than 1.

        unit : string, `~astropy.units.Unit`, optional
            Spectral flux density units for the output.  If ``None``,
            the default is W/(m2 μm) for wavelengths, Jy for
            frequencies.

        **kwargs
            Additional keyword arguments for
            `~synphot.observation.Observation`, e.g., ``force``.


        Returns
        -------
        fluxd : `~astropy.units.Quantity`
            The spectrum rebinned.


        Raises
        ------
        SinglePointSpectrumError - If requested wavelengths or
            frequencies has only one value.


        Notes
        -----
        Method for spectra adapted from AstroBetter post by Jessica Lu:
        https://www.astrobetter.com/blog/2013/08/12/python-tip-re-sampling-spectra-with-pysynphot/

        """

        from .. import units as sbu  # avoid circular dependency

        if np.size(wave_or_freq) == 1:
            raise SinglePointSpectrumError(
                'Multiple wavelengths or frequencies required for '
                'observe_spectrum.  Instead consider interpolation '
                'with {}().'.format(self.__class__.__name__))

        if unit is None:
            if wave_or_freq.unit.is_equivalent('m'):
                unit = u.Unit('W/(m2 um)')
            else:
                unit = u.Jy
        else:
            unit = u.Unit(unit)

        specele = synphot.SpectralElement(synphot.ConstFlux1D, amplitude=1)

        # Specele is defined over all wavelengths, but most spectral
        # standards are not.  force='taper' will affect retrieving
        # flux densities at the edges of the spectrum, but is
        # preferred to avoid wild extrapolation.
        kwargs['force'] = kwargs.get('force', 'taper')

        obs = synphot.Observation(self.source,
                                  specele,
                                  binset=wave_or_freq,
                                  **kwargs)

        if unit.is_equivalent(sbu.VEGAmag):
            fluxd = obs.sample_binned(flux_unit='W/(m2 um)').to(
                unit, sbu.spectral_density_vega(wave_or_freq))
        else:
            fluxd = obs.sample_binned(flux_unit=unit)

        return fluxd
    def get_sky_spectrum(self, return_type="table", filename=None):

        from astropy import table

        if filename is None:
            filename = "skycalc_temp.fits"

        if not self.validate_params():
            raise ValueError("Object contains invalid parameters. "
                             "Not calling ESO")

        skm = SkyModel()
        skm.callwith(self.values)
        skm.write(filename)

        with fits.open(filename) as hdu:

            tbl = table.Table(hdu[1].data)
            tbl["lam"].unit = u.um
            for colname in tbl.colnames:
                if "flux" in colname:
                    tbl[colname].unit = u.Unit("ph s-1 m-2 um-1 arcsec-2")

        date_created = dt.now().strftime('%Y-%m-%dT%H:%M:%S')
        meta_data = {
            "DESCRIPT": "Sky transmission and emission curves",
            "SOURCE": "ESO Skycalc utility",
            "AUTHOR": "ESO Skycalc utility",
            "STATUS": "Tested - Generated from ESO Skycalc utility",
            "DATE_CRE": date_created,
            "ETYPE": "TERCurve",
            "EDIM": 1
        }

        params = {k: (self.values[k], self.comments[k]) for k in self.keys}
        meta_data.update(params)

        if "tab" in return_type:
            tbl.meta.update(meta_data)

            if "ext" in return_type:
                tbl_return = tbl
            else:
                tbl_small = table.Table()
                tbl_small.add_columns([tbl["lam"], tbl["trans"], tbl["flux"]])
                tbl_return = tbl_small

            return tbl_return

        elif "arr" in return_type:

            wave = tbl["lam"].data * tbl["lam"].unit
            trans = tbl["trans"].data
            flux = tbl["flux"].data * tbl["flux"].unit

            return wave, trans, flux

        elif "syn" in return_type:
            import synphot as sp

            trans = sp.SpectralElement(sp.Empirical1D,
                                       points=tbl["lam"].data *
                                       tbl["lam"].unit,
                                       lookup_table=tbl["trans"].data)

            funit = u.Unit("ph s-1 m-2 um-1")
            flux = sp.SourceSpectrum(sp.Empirical1D,
                                     points=tbl["lam"].data * tbl["lam"].unit,
                                     lookup_table=tbl["flux"].data * funit)
            print("Warning: synphot doesn't accept surface brightnesses \n"
                  "The resulting spectrum should be multiplied by arcsec-2")

            return trans, flux

        elif "fit" in return_type:

            hdu0 = fits.PrimaryHDU()
            for key in meta_data:
                hdu0.header[key] = meta_data[key]
            hdu1 = fits.table_to_hdu(tbl)
            hdu = fits.HDUList([hdu0, hdu1])

            return hdu