Source code for exosim.tasks.foregrounds.estimateZodi

import astropy.units as u
from astropy.modeling.physical_models import BlackBody

import exosim.models.signal as signal
import exosim.utils.checks as checks
from exosim.tasks.task import Task


[docs]class EstimateZodi(Task): """ It estimate the zodiacal radiance in the target direction for a specific wavelength range Returns ------- :class:`~exosim.models.signal.Radiance` zodiacal radiance Examples -------- >>> estimateZodi = EstimateZodi() >>> wavelength = np.logspace(np.log10(0.45), np.log10(2.2), 6000) * u.um >>> zodi = estimateZodi(wavelength=wavelength, zodiacal_factor=1) or, given the pointing direction >>> zodi = self.estimateZodi(wavelength=wavelength, coordinates=(90 * u.deg, -66 * u.deg)) """ def __init__(self): """ Parameters ----------- wavelength: :class:`~numpy.ndarray` or :class:`~astropy.units.Quantity` wavelength grid. If no units are attached is considered as expressed in `um` zodiacal_factor: float zodiacal model multiplicative factor coordinates: (float, float) pointing coordinates as (ra, dec) zodi_map: str map file containing the zodiacal coefficients per sky positions. A default map is inclluded in ExoSim, that contains the coefficients fitted over Kelsall et al. 1998 model. """ self.add_task_param("wavelength", "wavelength range to investigate") self.add_task_param( "zodiacal_factor", "zodiacal multiplicative factor", None ) self.add_task_param("coordinates", "pointing direction", None) self.add_task_param( "zodi_map", " map file containing the zodiacal coefficients per sky positions", None, )
[docs] def execute(self): self.info("estimating zodiacal foreground") wl = self.get_task_param("wavelength") zodiacal_factor = self.get_task_param("zodiacal_factor") coordinates = self.get_task_param("coordinates") zodi_map = self.get_task_param("zodi_map") wl = checks.check_units(wl, u.um, self) if coordinates: zodiacal_factor = self.zodiacal_fit_direction( coordinates, zodi_map ) rad = self.model(zodiacal_factor, wl) self.debug("zodical radiance: {}".format(rad.data)) self.set_output(rad)
[docs] def model(self, a, wl): r""" The used zodiacal model is based on the zodiacal light model presented in Glasse et al. 2010 .. math:: I_{zodi}(\lambda) = a \left( 3.5 \cdot 10^{-14} BB(\lambda, 5500 \, K) + 3.52 \cdot 10^{-8} BB(\lambda, 270 \, K) \right) where :math:`BB(\lambda, T)` is the Planck black body law and :math:`a` is the fitted coefficient. Parameters ---------- a: float zodiacal multiplicative factor. Default is 0. wl: :class:`~numpy.ndarray` or :class:`~astropy.units.Quantity` wavelength grid. If no units are attached is considered as expressed in `um` Returns ------- :class:`~exosim.models.signal.Radiance` zodiacal radiance """ if not a: a = 0 units = u.W / (u.m**2 * u.um * u.sr) bb_1 = BlackBody(5500.0 * u.K) bb_1 = bb_1(wl).to(u.W / u.m**2 / u.sr / u.um, u.spectral_density(wl)) bb_2 = BlackBody(270.0 * u.K) bb_2 = bb_2(wl).to(u.W / u.m**2 / u.sr / u.um, u.spectral_density(wl)) zodi_emission = a * (3.5e-14 * bb_1 + 3.58e-8 * bb_2).to(units) return signal.Radiance(wl, zodi_emission)
[docs] def zodiacal_fit_direction(self, coordinates, zodi_map=None): r""" In this case the :math:`A` coefficient is selected by a precompiled grid. The grid has been estimated by fitting our model with Kelsall et al. (1998) data. A custom map can be provided, to replace the default one, as long as it matches the format. Parameters ---------- coordinates: (float, float) pointing coordinates as (ra, dec) zodi_map: str (optional) map file containing the zodiacal coefficients per sky positions. A default map is inclluded in ExoSim, that contains the coefficients fitted over Kelsall et al. 1998 model. Returns ------- float zodiacal factor for Glasse et al. 2010 zodiacal model """ import os from pathlib import Path import numpy as np from astropy.io.misc.hdf5 import read_table_hdf5 ra_input = coordinates[0] dec_input = coordinates[1] if zodi_map: zodi_map_file = zodi_map else: dir_path = Path(os.path.dirname(os.path.realpath(__file__))) i = 0 while ( "data" not in [d.stem for d in Path(dir_path).iterdir() if d.is_dir()] or i > 10 ): dir_path = dir_path.parent i += 1 if i > 10: self.error("default zodi map file not found") raise OSError("default zodi map file not found") data_path = os.path.join(dir_path.absolute().as_posix(), "data") zodi_map_file = os.path.join(data_path, "Zodi_map.hdf5") self.debug("map data:{}".format(zodi_map_file)) try: zodi_table = read_table_hdf5(zodi_map_file) self.debug(zodi_table) # here we find the minimun distance from the desired point distance = (zodi_table["ra_icrs"] * u.deg - ra_input) ** 2 + ( zodi_table["dec_icrs"] * u.deg - dec_input ) ** 2 idx = np.argmin(distance) # TODO implement an interpolator self.debug("selected line {}".format(idx)) self.debug(zodi_table[idx]) return zodi_table["zodi_coeff"][idx] except OSError: self.error("Zodi map file not found") raise OSError("Zodi map file not found")