Source code for species.util.radtrans_util
"""
Utility functions for ``petitRADTRANS`` spectra.
"""
from typing import Dict, List, Optional
import numpy as np
from typeguard import typechecked
from species.core.box import ModelBox
from species.read.read_radtrans import ReadRadtrans
[docs]
@typechecked
def retrieval_spectrum(
indices: Dict[str, np.int64],
chemistry: str,
pt_profile: str,
line_species: List[str],
cloud_species: List[str],
quenching: Optional[str],
spec_res: float,
distance: Optional[float],
pt_smooth: Optional[float],
temp_nodes: Optional[np.integer],
abund_nodes: Optional[np.integer],
abund_smooth: Optional[float],
read_rad: ReadRadtrans,
sample: np.ndarray,
) -> ModelBox:
"""
Function for calculating a petitRADTRANS spectrum
from a posterior sample.
Parameters
----------
indices : dict
Dictionary with the parameter indices for ``sample``.
chemistry : str
Chemistry type (``'equilibrium'`` or ``'free'``).
pt_profile : str
Pressure-temperature parametrization (``'molliere'``,
``'monotonic'``, or ``'free'``).
line_species : list(str)
List with the line species.
cloud_species : list(str)
List with the cloud species.
quenching : str, None
Quenching type for CO/CH4/H2O abundances. Either the quenching
pressure (bar) is a free parameter (``quenching='pressure'``)
or the quenching pressure is calculated from the mixing and
chemical timescales (``quenching='diffusion'``). The quenching
is not applied if the argument is set to ``None``.
spec_res : float
Spectral resolution.
distance : float, None
Distance (pc).
pt_smooth : float, None
Standard deviation of the Gaussian kernel that is used for
smoothing the sampled temperature nodes of the P-T profile.
Only required with `pt_profile='free'` or
`pt_profile='monotonic'`. The argument should be given as
log10(P/bar).
temp_nodes : int, None
Number of free temperature nodes that are used when
``pt_profile='monotonic'`` or ``pt_profile='free'``.
abund_nodes : int, None
Number of free abundance nodes that are used when
``chemistry='free'``.
abund_smooth : float, None
Standard deviation of the Gaussian kernel that is used for
smoothing the abundance profiles, after the abundance nodes
have been interpolated to a higher pressure resolution.
Only required with ```chemistry='free'```. The argument
should be given as :math:`\\log10{P/\\mathrm{bar}}`. No
smoothing is applied if the argument if set to 0 or ``None``.
read_rad : ReadRadtrans
Instance of :class:`~species.read.read_radtrans.ReadRadtrans`.
sample : np.ndarray
Parameter values with their order given by the ``indices``.
Returns
-------
species.core.box.ModelBox
Box with the petitRADTRANS spectrum.
"""
# Initiate parameter dictionary
model_param = {}
# Add log(g) and radius
model_param["logg"] = sample[indices["logg"]]
model_param["radius"] = sample[indices["radius"]]
# Add distance
if distance is not None:
model_param["distance"] = distance
# Add P-T profile parameters
if pt_profile == "molliere":
model_param["t1"] = sample[indices["t1"]]
model_param["t2"] = sample[indices["t2"]]
model_param["t3"] = sample[indices["t3"]]
model_param["log_delta"] = sample[indices["log_delta"]]
model_param["alpha"] = sample[indices["alpha"]]
model_param["tint"] = sample[indices["tint"]]
elif pt_profile == "gradient":
num_layer = 6 # could make a variable in the future
for index in range(num_layer):
model_param[f"PTslope_{num_layer - index}"] = sample[
indices[f"PTslope_{num_layer - index}"]
]
model_param["T_bottom"] = sample[indices["T_bottom"]]
elif pt_profile == "eddington":
model_param["log_delta"] = sample[indices["log_delta"]]
model_param["tint"] = sample[indices["tint"]]
elif pt_profile in ["free", "monotonic"]:
if temp_nodes is None:
# For backward compatibility
temp_nodes = 15
for j in range(temp_nodes):
model_param[f"t{j}"] = sample[indices[f"t{j}"]]
if pt_smooth is not None:
model_param["pt_smooth"] = pt_smooth
# Add chemistry parameters
if chemistry == "equilibrium":
model_param["c_o_ratio"] = sample[indices["c_o_ratio"]]
model_param["metallicity"] = sample[indices["metallicity"]]
elif chemistry == "free":
if abund_nodes is None:
for line_item in line_species:
model_param[line_item] = sample[indices[line_item]]
else:
for line_item in line_species:
for node_idx in range(abund_nodes):
model_param[f"{line_item}_{node_idx}"] = sample[
indices[f"{line_item}_{node_idx}"]
]
if abund_smooth is not None:
model_param["abund_smooth"] = abund_smooth
if quenching == "pressure":
model_param["log_p_quench"] = sample[indices["log_p_quench"]]
# Add cloud parameters
if "log_kappa_0" in indices:
model_param["log_kappa_0"] = sample[indices["log_kappa_0"]]
model_param["opa_index"] = sample[indices["opa_index"]]
model_param["log_p_base"] = sample[indices["log_p_base"]]
model_param["albedo"] = sample[indices["albedo"]]
if "fsed" in indices:
model_param["fsed"] = sample[indices["fsed"]]
elif "fsed_1" in indices and "fsed_2" in indices:
model_param["fsed_1"] = sample[indices["fsed_1"]]
model_param["fsed_2"] = sample[indices["fsed_2"]]
model_param["f_clouds"] = sample[indices["f_clouds"]]
if "opa_knee" in indices:
model_param["opa_knee"] = sample[indices["opa_knee"]]
elif "log_kappa_abs" in indices:
model_param["log_kappa_abs"] = sample[indices["log_kappa_abs"]]
model_param["opa_abs_index"] = sample[indices["opa_abs_index"]]
model_param["log_p_base"] = sample[indices["log_p_base"]]
model_param["fsed"] = sample[indices["fsed"]]
if "log_kappa_sca" in indices:
model_param["log_kappa_sca"] = sample[indices["log_kappa_sca"]]
model_param["opa_sca_index"] = sample[indices["opa_sca_index"]]
model_param["lambda_ray"] = sample[indices["lambda_ray"]]
elif "log_kappa_gray" in indices:
model_param["log_kappa_gray"] = sample[indices["log_kappa_gray"]]
model_param["log_cloud_top"] = sample[indices["log_cloud_top"]]
if "albedo" in indices:
model_param["albedo"] = sample[indices["albedo"]]
elif len(cloud_species) > 0:
if "fsed" in indices:
model_param["fsed"] = sample[indices["fsed"]]
else:
for item in cloud_species:
model_param[f"fsed_{item}"] = sample[indices[f"fsed_{item}"]]
model_param["sigma_lnorm"] = sample[indices["sigma_lnorm"]]
if "kzz" in indices:
# Backward compatibility
model_param["kzz"] = sample[indices["kzz"]]
elif "log_kzz" in indices:
model_param["log_kzz"] = sample[indices["log_kzz"]]
for cloud_item in cloud_species:
cloud_param = f"{cloud_item[:-3].lower()}_fraction"
if cloud_param in indices:
model_param[cloud_param] = sample[indices[cloud_param]]
cloud_param = f"{cloud_item[:-3].lower()}_tau"
if cloud_param in indices:
model_param[cloud_param] = sample[indices[cloud_param]]
if cloud_item in indices:
model_param[cloud_item] = sample[indices[cloud_item]]
if "log_tau_cloud" in indices:
model_param["tau_cloud"] = 10.0 ** sample[indices["log_tau_cloud"]]
if len(cloud_species) > 1:
for cloud_item in cloud_species[1:]:
cloud_1 = cloud_item[:-3].lower()
cloud_2 = cloud_species[0][:-3].lower()
cloud_ratio = f"{cloud_1}_{cloud_2}_ratio"
model_param[cloud_ratio] = sample[indices[cloud_ratio]]
# Add extinction parameters
if "ism_ext" in indices:
model_param["ism_ext"] = sample[indices["ism_ext"]]
if "ism_red" in indices:
model_param["ism_red"] = sample[indices["ism_red"]]
# Calculate spectrum
model_box = read_rad.get_model(model_param, spec_res=spec_res)
# Set content type of the ModelBox
model_box.type = "mcmc"
return model_box