Source code for species.util.model_util

"""
Utility functions for model spectra.
"""

import warnings

from typing import Dict, Tuple, Union

import numpy as np

from typeguard import typechecked

from species.core.box import ModelBox, create_box
from species.util.spec_util import create_wavelengths


[docs] @typechecked def convert_model_name(in_name: str) -> str: """ Function for updating a model name for use in plots. Parameters ---------- in_name : str Model name as used by species. Returns ------- str Updated model name for plots. """ if in_name == "drift-phoenix": out_name = "DRIFT-PHOENIX" elif in_name == "ames-cond": out_name = "AMES-Cond" elif in_name == "ames-dusty": out_name = "AMES-Dusty" elif in_name == "atmo": out_name = "ATMO" elif in_name == "atmo-ceq": out_name = "ATMO CEQ" elif in_name == "atmo-neq-weak": out_name = "ATMO NEQ weak" elif in_name == "atmo-neq-strong": out_name = "ATMO NEQ strong" elif in_name == "petrus2023": out_name = "ATMO (Petrus et al. 2023)" elif in_name == "atmo-petrus2023": out_name = "ATMO (Petrus et al. 2023)" elif in_name == "bt-cond": out_name = "BT-Cond" elif in_name == "bt-cond-feh": out_name = "BT-Cond" elif in_name == "bt-settl": out_name = "BT-Settl" elif in_name == "bt-settl-cifist": out_name = "BT-Settl" elif in_name == "bt-nextgen": out_name = "BT-NextGen" elif in_name == "bt-nextgen-subsolar": out_name = "BT-NextGen" elif in_name == "koester-wd": out_name = "Koester (2010)" elif in_name == "petitcode-cool-clear": out_name = "petitCODE clear" elif in_name == "petitcode-cool-cloudy": out_name = "petitCODE cloudy" elif in_name == "petitcode-hot-clear": out_name = "petitCODE clear" elif in_name == "petitcode-hot-cloudy": out_name = "petitCODE cloudy" elif in_name == "petitcode-linder2019-clear": out_name = "petitCODE clear (Linder et al. 2019)" elif in_name == "petitcode-linder2019-cloudy": out_name = "petitCODE cloudy (Linder et al. 2019)" elif in_name == "exo-rem": out_name = "Exo-REM" elif in_name == "exo-rem-highres": out_name = "Exo-REM" elif in_name in ["planck", "blackbody"]: out_name = "Blackbody" elif in_name == "zhu2015": out_name = "Zhu (2015)" elif in_name == "saumon2008-clear": out_name = "Saumon & Marley (2008)" elif in_name == "saumon2008-cloudy": out_name = "Saumon & Marley (2008)" elif in_name == "sonora-cholla": out_name = "Sonora Cholla" elif in_name == "sonora-bobcat": out_name = "Sonora Bobcat" elif in_name == "sonora-bobcat-co": out_name = "Sonora Bobcat C/O" elif in_name == "sonora-elfowl-l": out_name = "Sonora Elf Owl" elif in_name == "sonora-elfowl-t": out_name = "Sonora Elf Owl" elif in_name == "sonora-elfowl-y": out_name = "Sonora Elf Owl" elif in_name == "sphinx": out_name = "SPHINX" elif in_name == "petitradtrans": out_name = "petitRADTRANS" else: out_name = in_name warnings.warn( f"The model name '{in_name}' is not known " "so the output name will not get adjusted " "for plot purposes" ) return out_name
[docs] @typechecked def powerlaw_spectrum( wavel_range: Union[Tuple[float, float], Tuple[np.float32, np.float32]], model_param: Dict[str, float], spec_res: float = 100.0, ) -> ModelBox: """ Function for calculating a power-law spectrum. The power-law function is calculated in log(wavelength)-log(flux) space but stored in the :class:`~species.core.box.ModelBox` in linear wavelength-flux space. Parameters ---------- wavel_range : tuple(float, float) Tuple with the minimum and maximum wavelength (um). model_param : dict Dictionary with the model parameters. Should contain `'log_powerlaw_a'`, `'log_powerlaw_b'`, and `'log_powerlaw_c'`. spec_res : float Spectral resolution (default: 100). Returns ------- species.core.box.ModelBox Box with the power-law spectrum. """ wavel = create_wavelengths((wavel_range[0], wavel_range[1]), spec_res) wavel *= 1e3 # (um) -> (nm) log_flux = ( model_param["log_powerlaw_a"] + model_param["log_powerlaw_b"] * np.log10(wavel) ** model_param["log_powerlaw_c"] ) model_box = create_box( boxtype="model", model="powerlaw", wavelength=1e-3 * wavel, # (um) flux=10.0**log_flux, # (W m-2 um-1) parameters=model_param, quantity="flux", ) return model_box
[docs] @typechecked def gaussian_spectrum( wavel_range: Union[Tuple[float, float], Tuple[np.float32, np.float32]], model_param: Dict[str, float], spec_res: float = 100.0, double_gaussian: bool = False, ) -> ModelBox: """ Function for calculating a Gaussian spectrum (i.e. for an emission line). Parameters ---------- wavel_range : tuple(float, float) Tuple with the minimum and maximum wavelength (um). model_param : dict Dictionary with the model parameters. Should contain ``'gauss_amplitude'``, ``'gauss_mean'``, ``'gauss_sigma'``, and optionally ``'gauss_offset'``. spec_res : float Spectral resolution (default: 100). double_gaussian : bool Set to ``True`` for returning a double Gaussian function. In that case, ``model_param`` should also contain ``'gauss_amplitude_2'``, ``'gauss_mean_2'``, and ``'gauss_sigma_2'``. Returns ------- species.core.box.ModelBox Box with the Gaussian spectrum. """ wavel = create_wavelengths((wavel_range[0], wavel_range[1]), spec_res) gauss_exp = np.exp( -0.5 * (wavel - model_param["gauss_mean"]) ** 2 / model_param["gauss_sigma"] ** 2 ) flux = model_param["gauss_amplitude"] * gauss_exp if double_gaussian: gauss_exp = np.exp( -0.5 * (wavel - model_param["gauss_mean_2"]) ** 2 / model_param["gauss_sigma_2"] ** 2 ) flux += model_param["gauss_amplitude_2"] * gauss_exp if "gauss_offset" in model_param: flux += model_param["gauss_offset"] model_box = create_box( boxtype="model", model="gaussian", wavelength=wavel, flux=flux, parameters=model_param, quantity="flux", ) return model_box
# @typechecked # def add_luminosity(modelbox: ModelBox) -> ModelBox: # """ # Function to add the luminosity of a model spectrum to the parameter # dictionary of the box. # # Parameters # ---------- # modelbox : species.core.box.ModelBox # Box with the model spectrum. Should also contain the dictionary # with the model parameters, the radius in particular. # # Returns # ------- # species.core.box.ModelBox # The input box with the luminosity added in the parameter # dictionary. # """ # # print("Calculating the luminosity...", end="", flush=True) # # if modelbox.model == "planck": # readmodel = ReadPlanck(wavel_range=(1e-1, 1e3)) # fullspec = readmodel.get_spectrum( # model_param=modelbox.parameters, spec_res=1000.0 # ) # # else: # readmodel = ReadModel(modelbox.model) # fullspec = readmodel.get_model(modelbox.parameters) # # flux = simps(fullspec.flux, fullspec.wavelength) # # if "parallax" in modelbox.parameters: # luminosity = ( # 4.0 # * np.pi # * (1e3 * constants.PARSEC / fullspec.parameters["parallax"]) ** 2 # * flux # ) # (W) # # elif "distance" in modelbox.parameters: # luminosity = ( # 4.0 # * np.pi # * (fullspec.parameters["distance"] * constants.PARSEC) ** 2 # * flux # ) # (W) # # # Analytical solution for a single-component Planck function # # luminosity = 4.*np.pi*(modelbox.parameters['radius']*constants.R_JUP)**2* \ # # constants.SIGMA_SB*modelbox.parameters['teff']**4. # # else: # luminosity = ( # 4.0 * np.pi * (fullspec.parameters["radius"] * constants.R_JUP) ** 2 * flux # ) # (W) # # modelbox.parameters["luminosity"] = luminosity / constants.L_SUN # (Lsun) # # print(" [DONE]") # # print( # f"Wavelength range (um): {fullspec.wavelength[0]:.2e} - " # f"{fullspec.wavelength[-1]:.2e}" # ) # # print(f"Luminosity (Lsun): {luminosity/constants.L_SUN:.2e}") # # return modelbox
[docs] @typechecked def binary_to_single(param_dict: Dict[str, float], star_index: int) -> Dict[str, float]: """ Function for converting a dictionary with atmospheric parameters of a binary system to a dictionary of parameters for one of the two stars. Parameters ---------- param_dict : dict Dictionary with the atmospheric parameters of both stars. The keywords end either with ``_0`` or ``_1`` that correspond with ``star_index=0`` or ``star_index=1``. star_index : int Star index (0 or 1) that is used for the parameters in ``param_dict``. Returns ------- dict Dictionary with the parameters of the selected star. """ new_dict = {} for key, value in param_dict.items(): if star_index == 0 and key[-1] == "0": new_dict[key[:-2]] = value elif star_index == 1 and key[-1] == "1": new_dict[key[:-2]] = value elif key in [ "teff", "logg", "feh", "c_o_ratio", "fsed", "radius", "distance", "parallax", ]: new_dict[key] = value return new_dict