Source code for synphot.thermal
# Licensed under a 3-clause BSD style license - see LICENSE.rst
"""This module defines thermal spectra."""
# ASTROPY
from astropy import units as u
from astropy.io import fits
from astropy.io.fits.connect import is_fits
# LOCAL
from synphot import exceptions, specio, units
from synphot.models import BlackBody1D, Empirical1D
from synphot.spectrum import BaseUnitlessSpectrum, SourceSpectrum
__all__ = ['ThermalSpectralElement']
[docs]
class ThermalSpectralElement(BaseUnitlessSpectrum):
"""Class to handle spectral element with associated thermal
properties.
This differs from `~synphot.spectrum.SpectralElement` in the
sense that it carries thermal parameters, i.e., temperature
and beam filling factor.
.. note::
Use :func:`thermal_source` to apply its emissivity to an
existing beam.
Parameters
----------
modelclass, kwargs
See `~synphot.spectrum.BaseSpectrum`.
temperature : float or `~astropy.units.quantity.Quantity`
Temperature. If not a Quantity, assumed to be in Kelvin.
beam_fill_factor : float or `~astropy.units.quantity.Quantity`
Beam filling factor. If a Quantity, must be unitless.
Defaults to 1.
"""
def __init__(self, modelclass, temperature, beam_fill_factor=1, **kwargs):
super(ThermalSpectralElement, self).__init__(modelclass, **kwargs)
self.temperature = temperature
self.beam_fill_factor = beam_fill_factor
@property
def temperature(self):
"""Temperature."""
return self._temperature
@temperature.setter
def temperature(self, what):
"""Set temperature."""
self._temperature = units.validate_quantity(what, u.K)
@property
def beam_fill_factor(self):
"""Beam filling factor."""
return self._beam_fill_factor
@beam_fill_factor.setter
def beam_fill_factor(self, what):
"""Set beam filling factor."""
self._beam_fill_factor = units.validate_quantity(what, '').value
[docs]
def taper(self, **kwargs):
"""Tapering is disabled."""
raise NotImplementedError(
'Thermal spectral element cannot be tapered.')
[docs]
def thermal_source(self):
"""Apply emissivity to an existing beam to produce a thermal
source spectrum (without optical counterpart).
Thermal source spectrum is calculated as follow:
#. Create a blackbody spectrum in PHOTLAM per square arcsec
with `temperature`.
#. Multiply the blackbody with `beam_fill_factor` and ``self``.
Returns
-------
sp : `~synphot.spectrum.SourceSpectrum`
Thermal source spectrum.
"""
sp = (SourceSpectrum(BlackBody1D, temperature=self.temperature) *
units.SR_PER_ARCSEC2 * self.beam_fill_factor * self)
sp.meta['temperature'] = self.temperature
sp.meta['beam_fill_factor'] = self.beam_fill_factor
return sp
[docs]
@classmethod
def from_file(cls, filename, temperature_key='DEFT',
beamfill_key='BEAMFILL', **kwargs):
"""Creates a thermal spectral element from file.
.. note::
Only FITS format is supported.
Parameters
----------
filename : str
Thermal spectral element filename.
temperature_key, beamfill_key : str
Keywords in FITS *table extension* that store temperature
(in Kelvin) and beam filling factor values.
Beam filling factor is set to 1 if its keyword is missing.
kwargs : dict
Keywords acceptable by :func:`~synphot.specio.read_fits_spec`.
Returns
-------
th : `ThermalSpectralElement`
Empirical thermal spectral element.
Raises
------
synphot.exceptions.SynphotError
Invalid inputs.
"""
if not is_fits("", filename, None):
raise exceptions.SynphotError('Only FITS format is supported.')
# Extra info from table header
ext = kwargs.get('ext', 1)
tab_hdr = fits.getheader(filename, ext=ext)
temperature = tab_hdr.get(temperature_key)
if temperature is None:
raise exceptions.SynphotError(
'Missing {0} keyword.'.format(temperature_key))
beam_fill_factor = tab_hdr.get('BEAMFILL', 1)
if 'flux_col' not in kwargs:
kwargs['flux_col'] = 'EMISSIVITY'
header, wavelengths, em = specio.read_spec(filename, **kwargs)
return cls(
Empirical1D, temperature, beam_fill_factor=beam_fill_factor,
points=wavelengths, lookup_table=em, meta={'header': header})