def test_returns_correct_photon_counts_when_scaled_to_vega_zero(self):
        src = stars("Generic/Johnson.V", [0] * u.mag, ["A0V"], [0], [0])

        filt = tcu.get_filter("Generic/Johnson.J")
        obs = sp.Observation(src.spectra[0], filt)
        assert obs.effstim(sp.units.PHOTLAM).value == approx(193, rel=0.01)

        filt = tcu.get_filter("Generic/Johnson.I")
        obs = sp.Observation(src.spectra[0], filt)
        assert obs.effstim(u.Jansky).value == approx(2367, rel=0.01)
Beispiel #2
0
    def observe_bandpass(self, bp, unit=None, **kwargs):
        """Observe through a bandpass.


        Parameters
        ----------
        bp : `~synphot.SpectralElement`, list, or tuple
            Bandpass.

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

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


        Returns
        -------
        lambda_eff : `~astropy.units.Quantity`
            Effective wavelength(s) of the observation(s).

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

        """

        from .. import units as sbu  # avoid circular dependency

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

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

        fluxd = np.ones(len(bp)) * unit
        for i in range(len(bp)):
            obs = synphot.Observation(self.source, bp[i], **kwargs)
            lambda_eff = obs.effective_wavelength()
            lambda_pivot = obs.bandpass.pivot()
            _fluxd = obs.effstim('W/(m2 um)')

            if unit.is_equivalent(sbu.VEGAmag):
                fluxd[i] = _fluxd.to(unit, sbu.spectral_density_vega(bp[i]))
            else:
                fluxd[i] = _fluxd.to(unit, u.spectral_density(lambda_pivot))

        if np.ndim(fluxd) != ndim:
            fluxd = fluxd.squeeze()

        return lambda_eff, fluxd
Beispiel #3
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
Beispiel #4
0
    def filt(self, bp, unit='W / (m2 um)', **kwargs):
        """Observe source through a single filter.

        Parameters
        ----------
        bp: string or `~synphot.SpectralElement`
            The name of a filter, or a transmission spectrum as a
            `~synphot.SpectralElement`.  See Notes for built-in filter
            names.

        unit: string, `~astropy.units.Unit`, optional
            Spectral flux density units of the output.

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

        Returns
        -------
        wave: `~astropy.units.Quantity`
            Effective wavelength.

        fluxd: `~astropy.units.Quantity` or float
            Spectral flux density.

        Notes
        -----

        Filter reference data is from STScI's Calibration Reference
        Data System.

        * ``'bessel_j'`` (Bessel * J*)
        * ``'bessel_h'`` (Bessel * H*)
        * ``'bessel_k'`` (Bessel * K*)
        * ``'cousins_r'`` (Cousins * R*)
        * ``'cousins_i'`` (Cousins * I*)
        * ``'johnson_u'`` (Johnson * U*)
        * ``'johnson_b'`` (Johnson * B*)
        * ``'johnson_v'`` (Johnson * V*)
        * ``'johnson_r'`` (Johnson * R*)
        * ``'johnson_i'`` (Johnson * I*)
        * ``'johnson_j'`` (Johnson * J*)
        * ``'johnson_k'`` (Johnson * K*)

        """

        import synphot

        from .. import units as sbu  # avoid circular dependency

        if isinstance(bp, str):
            bp = synphot.SpectralElement.from_filter(bp)

        obs = synphot.Observation(self.source, bp, **kwargs)
        wave = obs.effective_wavelength()
        _unit = u.Unit(unit)

        if _unit.is_equivalent(sbu.VEGAmag):
            fluxd = obs.effstim('W/(m2 um)').to(_unit,
                                                sbu.spectral_density_vega(bp))
        else:
            fluxd = obs.effstim(flux_unit=_unit)

        return wave, fluxd
Beispiel #5
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
 def test_returns_correct_photon_count_when_scaled_to_jansky(self):
     src = stars("Generic/Johnson.V", [3631] * u.Jansky, ["A0V"], [0], [0])
     filt = tcu.get_filter("Paranal/HAWKI.J")
     obs = sp.Observation(src.spectra[0], filt)
     phs = obs.effstim(sp.units.PHOTLAM).value * src.fields[0]["weight"][0]
     assert phs == approx(210, rel=0.01)
 def test_returns_correct_photon_count_when_initialised_in_hawki_j(self):
     src = stars("Paranal/HAWKI.J", [0] * u.mag, ["A0V"], [0], [0])
     filt = tcu.get_filter("Paranal/HAWKI.J")
     obs = sp.Observation(src.spectra[0], filt)
     assert obs.effstim(sp.units.PHOTLAM).value == approx(210, rel=0.01)
Beispiel #8
0
    def filt(self, bp, unit='W / (m2 um)', **kwargs):
        """Spectrum observed through a filter.

        Parameters
        ----------
        bp : string or `~synphot.SpectralElement`
          The name of a filter, or a transmission spectrum as a
          `~synphot.SpectralElement`.  See notes for built-in filter
          names.

        unit : string, `~astropy.units.Unit`, optional
          Spectral units of the output: flux density, 'vegamag',
          'ABmag', or 'STmag'.  See :ref:`sbpy_spectral_standards`
          for calibration notes.

        **kwargs
          Additional keyword arguments for
          `~synphot.observation.Observation`.

        Returns
        -------
        wave : `~astropy.units.Quantity`
          Effective wavelength.

        fluxd : `~astropy.units.Quantity` or float
          Flux density or magnitude.


        Notes
        -----

        Filter reference data is from STScI's Calibration Reference
        Data System.

        * ``'bessel_j'`` (Bessel *J*)
        * ``'bessel_h'`` (Bessel *H*)
        * ``'bessel_k'`` (Bessel *K*)
        * ``'cousins_r'`` (Cousins *R*)
        * ``'cousins_i'`` (Cousins *I*)
        * ``'johnson_u'`` (Johnson *U*)
        * ``'johnson_b'`` (Johnson *B*)
        * ``'johnson_v'`` (Johnson *V*)
        * ``'johnson_r'`` (Johnson *R*)
        * ``'johnson_i'`` (Johnson *I*)
        * ``'johnson_j'`` (Johnson *J*)
        * ``'johnson_k'`` (Johnson *K*)

        """

        import synphot
        from synphot.units import VEGAMAG
        from .vega import Vega
        from ..units import spectral_density_vega

        if isinstance(bp, str):
            bp = synphot.SpectralElement.from_filter(bp)

        if not isinstance(bp, synphot.SpectralElement):
            raise ValueError('`bp` must be a string (filter name) or'
                             ' `synphot.SpectralElement`.')

        obs = synphot.Observation(self.source, bp, **kwargs)
        wave = obs.effective_wavelength()
        _unit = u.Unit(unit)

        if _unit.is_equivalent(VEGAMAG):
            fluxd = obs.effstim('W/(m2 um)').to(_unit,
                                                spectral_density_vega(bp))
        else:
            fluxd = obs.effstim(_unit)

        return wave, fluxd
Beispiel #9
0
 def make_cluster_rates(self, masses, ins, bandpass=None):
     filter = ins.filter
     instrument = ins.DETECTOR
     try:
         coords = np.load(os.path.join(self.gridpath, 'input.npy'),
                          allow_pickle=True)
     except UnicodeError:
         coords = np.load(os.path.join(self.gridpath, 'input.npy'),
                          allow_pickle=True,
                          encoding='bytes')
     m, t, g, i = self.get_star_info()
     temps = np.interp(masses, m, t)
     gravs = np.interp(masses, m, g)
     mags = np.interp(masses, m, i)
     metals = np.full_like(mags, self.metallicity)
     if os.path.exists(
             os.path.join(
                 self.gridpath,
                 'result_{}_{}.npy'.format(instrument.lower(),
                                           filter.lower()))):
         values = np.load(os.path.join(
             self.gridpath,
             'result_{}_{}.npy'.format(instrument.lower(), filter.lower())),
                          allow_pickle=True)
         interpolation_function = RegularGridInterpolator(
             tuple([x for x in coords]), values)
         try:
             countrates = interpolation_function(
                 np.array((metals, gravs, temps, mags)).T)
         except ValueError as v:
             self.log('error',
                      'Exception caught when interpolating: {}'.format(v))
             min_mag = coords[-1][0]
             max_mag = coords[-1][-1]
             interpolation_function = RegularGridInterpolator(
                 tuple([x for x in coords]),
                 values,
                 bounds_error=False,
                 fill_value=0.)
             mags_min = np.full_like(mags, min_mag)
             mags_max = np.full_like(mags, max_mag)
             countrates = interpolation_function(
                 np.array((metals, gravs, temps, mags)).T)
             countrates_min = interpolation_function(
                 np.array((metals, gravs, temps, mags_min)).T)
             countrates_min = countrates_min * np.power(
                 10, -(mags - min_mag) / 2.512)
             countrates_max = interpolation_function(
                 np.array((metals, gravs, temps, mags_max)).T)
             countrates_max = countrates_max * np.power(
                 10, -(mags - max_mag) / 2.512)
             countrates[np.where(
                 mags < mags_min)] = countrates_min[np.where(
                     mags < mags_min)]
             countrates[np.where(
                 mags > mags_max)] = countrates_max[np.where(
                     mags > mags_max)]
     else:
         self.log(
             'warning',
             'Could not find result file "result_{}_{}.npy" from {}'.format(
                 instrument.lower(), filter.lower(), self.gridpath))
         #             raise FileNotFoundError('Could not find result file "result_{}_{}.npy" from {}'.format(instrument.lower(), filter.lower(), self.gridpath))
         import synphot as syn
         import stsynphot as stsyn
         countrates = np.array(())
         johnson_i = syn.SpectralElement.from_filter('johnson_i')
         for te, log_g, z, j_i in zip(temps, gravs, metals, mags):
             spectrum = stsyn.grid_to_spec('phoenix', te, z, log_g)
             spectrum = spectrum.normalize(u.Magnitude(j_i), johnson_i)
             obs = syn.Observation(spectrum,
                                   bandpass,
                                   binset=spectrum.waveset)
             countrates = np.append(countrates, obs.countrate(ins.AREA))
             self.log(
                 'info', 'Manually created star {} of {}'.format(
                     len(countrates), len(temps)))
     return countrates
Beispiel #10
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
Beispiel #11
0
                    counts = False
                    if np.sum(spec(spec.waveset)) > 0.:
                        counts = True
                except stsyn.exceptions.ParameterOutOfBounds:
                    counts = False
                for l, mag in enumerate(coords[3]):
                    msg = "\t\t\t{:6d} of {}: {}: Starting Z = {}, log(g) = {}, Teff = {:7.1f}, Mabs = {:>4}"
                    print(msg.format(n+1, total, time.ctime(), Z, logg, teff, mag), end='')
                    if counts:
                        norm_value = mag*u.ABmag
                        spec_norm = spec.normalize(norm_value, norm_bandpass)
                    for instrument in instruments:
                        for mode in modes[instrument.lower()]:
                            for filter in filters[instrument.lower()][mode]:
                                if counts:
                                    obs = syn.Observation(spec_norm, bandpasses[instrument.lower()][filter], binset=spec_norm.waveset)
                                    result_arrays[instrument.lower()][filter][i,j,k,l] = obs.countrate(area[instrument.lower()]).value
                                    print(".", end='')
                                else:
                                    result_arrays[instrument.lower()][filter][i,j,k,l] = 0.
                                    print("x", end='')
                    print("")
                    n += 1


    print("{}: Saving files...".format(time.ctime()), end='')
    with open(os.path.join(os.getcwd(), "grid", "VERSION.txt"), "wt") as outf:
        outf.write("Pandeia: {}\n".format(pandeia_version_info))
        outf.write("STIPS: {}\n".format(stips_version_info))
    np.save(os.path.join(os.getcwd(), 'grid', 'input.npy'), coords)
    for instrument in instruments: