"""
Module with reading functionalities for Planck spectra.
"""
import os
import math
import configparser
import numpy as np
from species.analysis import photometry
from species.core import box, constants
from species.read import read_filter
[docs]class ReadPlanck:
"""
Class for reading a Planck spectrum.
"""
def __init__(self,
wavel_range=None,
filter_name=None):
"""
Parameters
----------
wavel_range : tuple(float, float), None
Wavelength range (um). A wavelength range of 0.1-1000 um is used if set to
None. Not used if ``filter_name`` is not None.
filter_name : str, None
Filter name that is used for the wavelength range. The ``wavel_range`` is used if set
to None.
Returns
-------
NoneType
None
"""
self.spectrum_interp = None
self.wl_points = None
self.wl_index = None
self.filter_name = filter_name
self.wavel_range = wavel_range
if self.filter_name is not None:
transmission = read_filter.ReadFilter(self.filter_name)
self.wavel_range = transmission.wavelength_range()
elif self.wavel_range is None:
self.wavel_range = (0.1, 1000.)
config_file = os.path.join(os.getcwd(), 'species_config.ini')
config = configparser.ConfigParser()
config.read_file(open(config_file))
self.database = config['species']['database']
[docs] @staticmethod
def planck(wavel_points,
temperature,
scaling):
"""
Internal function for calculating a Planck function.
Parameters
----------
wavel_points : numpy.ndarray
Wavelength points (um).
temperature : float
Temperature (K).
scaling : float
Scaling parameter.
Returns
-------
numpy.ndarray
Flux density (W m-2 um-1).
"""
planck_1 = 2.*constants.PLANCK*constants.LIGHT**2/(1e-6*wavel_points)**5
planck_2 = np.exp(constants.PLANCK*constants.LIGHT /
(1e-6*wavel_points*constants.BOLTZMANN*temperature)) - 1.
return 1e-6 * math.pi * scaling * planck_1/planck_2 # (W m-2 um-1)
[docs] @staticmethod
def update_parameters(model_param):
"""
Internal function for updating the dictionary with model parameters.
Parameters
----------
model_param : dict
Dictionary with the 'teff' (K), 'radius' (Rjup), and 'distance' (pc). The values
of 'teff' and 'radius' can be a single float, or a list with floats for a combination
of multiple Planck functions, e.g.
{'teff': [1500., 1000.], 'radius': [1., 2.], 'distance': 10.}.
Returns
-------
dict
Updated dictionary with model parameters.
"""
updated_param = {}
for i, _ in enumerate(model_param['teff']):
updated_param[f'teff_{i}'] = model_param['teff'][i]
updated_param[f'radius_{i}'] = model_param['radius'][i]
updated_param['distance'] = model_param['distance']
return updated_param
[docs] def get_spectrum(self,
model_param,
spec_res):
"""
Function for calculating a Planck spectrum or a combination of multiple Planck spectra.
Parameters
----------
model_param : dict
Dictionary with the 'teff' (K), 'radius' (Rjup), and 'distance' (pc). The values
of 'teff' and 'radius' can be a single float, or a list with floats for a combination
of multiple Planck functions, e.g.
{'teff': [1500., 1000.], 'radius': [1., 2.], 'distance': 10.}.
spec_res : float
Spectral resolution.
Returns
-------
species.core.box.ModelBox
Box with the Planck spectrum.
"""
if 'teff' in model_param and isinstance(model_param['teff'], list):
model_param = self.update_parameters(model_param)
wavel_points = [self.wavel_range[0]]
while wavel_points[-1] <= self.wavel_range[1]:
wavel_points.append(wavel_points[-1] + wavel_points[-1]/(2.*spec_res))
wavel_points = np.asarray(wavel_points) # (um)
n_planck = (len(model_param)-1) // 2
if n_planck == 1:
scaling = ((model_param['radius']*constants.R_JUP) /
(model_param['distance']*constants.PARSEC))**2
flux = self.planck(np.copy(wavel_points),
model_param['teff'],
scaling) # (W m-2 um-1)
else:
flux = np.zeros(wavel_points.shape)
for i in range(n_planck):
scaling = ((model_param[f'radius_{i}']*constants.R_JUP) /
(model_param['distance']*constants.PARSEC))**2
flux += self.planck(np.copy(wavel_points),
model_param[f'teff_{i}'],
scaling) # (W m-2 um-1)
return box.create_box(boxtype='model',
model='planck',
wavelength=wavel_points,
flux=flux,
parameters=model_param,
quantity='flux')
[docs] def get_flux(self,
model_param,
synphot=None):
"""
Function for calculating the average flux density for the ``filter_name``.
Parameters
----------
model_param : dict
Dictionary with the 'teff' (K), 'radius' (Rjup), and 'distance' (pc).
synphot : species.analysis.photometry.SyntheticPhotometry, None
Synthetic photometry object. The object is created if set to None.
Returns
-------
float
Average flux density (W m-2 um-1).
"""
if 'teff' in model_param and isinstance(model_param['teff'], list):
model_param = self.update_parameters(model_param)
spectrum = self.get_spectrum(model_param, 100.)
if synphot is None:
synphot = photometry.SyntheticPhotometry(self.filter_name)
return synphot.spectrum_to_flux(spectrum.wavelength, spectrum.flux)
[docs] def get_magnitude(self,
model_param,
synphot=None):
"""
Function for calculating the magnitude for the ``filter_name``.
Parameters
----------
model_param : dict
Dictionary with the 'teff' (K), 'radius' (Rjup), and 'distance' (pc).
synphot : species.analysis.photometry.SyntheticPhotometry, None
Synthetic photometry object. The object is created if set to None.
Returns
-------
float
Apparent magnitude (mag).
float
Absolute magnitude (mag)
"""
if 'teff' in model_param and isinstance(model_param['teff'], list):
model_param = self.update_parameters(model_param)
spectrum = self.get_spectrum(model_param, 100.)
if synphot is None:
synphot = photometry.SyntheticPhotometry(self.filter_name)
return synphot.spectrum_to_magnitude(spectrum.wavelength,
spectrum.flux,
distance=(model_param['distance'], None))
[docs] def get_color_magnitude(self,
temperatures,
radius,
filters_color,
filter_mag):
"""
Function for calculating the colors and magnitudes in the range of 100-10000 K.
Parameters
----------
temperatures : numpy.ndarray
Temperatures (K) for which the colors and magnitude are calculated.
radius : float
Radius (Rjup).
filters_color : tuple(str, str)
Filter names for the color.
filter_mag : str
Filter name for the absolute magnitudes.
Returns
-------
species.core.box.ColorMagBox
Box with the colors and magnitudes.
"""
list_color = []
list_mag = []
for item in temperatures:
model_param = {'teff': item, 'radius': radius, 'distance': 10.}
read_planck_0 = ReadPlanck(filter_name=filters_color[0])
read_planck_1 = ReadPlanck(filter_name=filters_color[1])
read_planck_2 = ReadPlanck(filter_name=filter_mag)
app_mag_0, _ = read_planck_0.get_magnitude(model_param)
app_mag_1, _ = read_planck_1.get_magnitude(model_param)
app_mag_2, _ = read_planck_2.get_magnitude(model_param)
list_color.append(app_mag_0[0]-app_mag_1[0])
list_mag.append(app_mag_2[0])
return box.create_box(boxtype='colormag',
library='planck',
object_type=None,
filters_color=filters_color,
filter_mag=filter_mag,
color=list_color,
magnitude=list_mag,
sptype=temperatures)
[docs] def get_color_color(self,
temperatures,
radius,
filters_colors):
"""
Function for calculating two colors in the range of 100-10000 K.
Parameters
----------
temperatures : numpy.ndarray
Temperatures (K) for which the colors are calculated.
radius : float
Radius (Rjup).
filters_colors : tuple(tuple(str, str), tuple(str, str))
Two tuples with the filter names for the colors.
Returns
-------
species.core.box.ColorColorBox
Box with the colors.
"""
list_color_1 = []
list_color_2 = []
for item in temperatures:
model_param = {'teff': item, 'radius': radius, 'distance': 10.}
read_planck_0 = ReadPlanck(filter_name=filters_colors[0][0])
read_planck_1 = ReadPlanck(filter_name=filters_colors[0][1])
read_planck_2 = ReadPlanck(filter_name=filters_colors[1][0])
read_planck_3 = ReadPlanck(filter_name=filters_colors[1][1])
app_mag_0, _ = read_planck_0.get_magnitude(model_param)
app_mag_1, _ = read_planck_1.get_magnitude(model_param)
app_mag_2, _ = read_planck_2.get_magnitude(model_param)
app_mag_3, _ = read_planck_3.get_magnitude(model_param)
list_color_1.append(app_mag_0[0]-app_mag_1[0])
list_color_2.append(app_mag_2[0]-app_mag_3[0])
return box.create_box(boxtype='colorcolor',
library='planck',
object_type=None,
filters=filters_colors,
color1=list_color_1,
color2=list_color_2,
sptype=temperatures)