Source code for sheap.Utils.BasicFunctions

"""
Basic Functions
===============

This module provides core physical conversions frequently used in 
spectral analysis, including wavelength ↔ velocity conversions and 
vacuum ↔ air wavelength corrections.

Functions
---------
kms_to_wl(kms, line_center, C_KMS=DEFAULT_DEFAULT_C_KMS)
    Convert velocity in km/s to a wavelength shift at a given line center.

wl_to_kms(wl, line_center, C_KMS=DEFAULT_DEFAULT_C_KMS)
    Convert wavelength shift to velocity in km/s at a given line center.

vac_to_air(lam_vac)
    Convert vacuum wavelengths to air wavelengths using the IAU standard.
"""

__author__ = 'felavila'

__all__ = [
    "kms_to_wl",
    "vac_to_air",
    "wl_to_kms",
]


from typing import Callable, Dict, Optional, Tuple

import jax.numpy as jnp
import numpy as np
from uncertainties import unumpy as unp

from sheap.Utils.Constants  import DEFAULT_C_KMS

def log10(x):
    """
    Compute base-10 logarithm for both numpy arrays and
    uncertainties.unumpy arrays, replacing non-positive values with NaN.

    Parameters
    ----------
    x : array-like or unumpy.uarray
        Input values.

    Returns
    -------
    result : array-like
        log10(x), with non-positive values replaced by NaN.
        Uses np.log10 for pure numpy objects, or unp.log10 if x has uncertainties.
    """
   
    if isinstance(x, np.ndarray) and x.dtype == object and x.size:
        # convert to unumpy array if not already
        vals = unp.nominal_values(x)
        safe = unp.uarray(np.where(vals > 0, vals, np.nan),
                             unp.std_devs(x))
        return unp.log10(safe)

    
    x = np.asarray(x, dtype=float)
    safe = np.where(x > 0, x, np.nan)
    return np.log10(safe)

[docs] def kms_to_wl(kms, line_center, C_KMS=DEFAULT_C_KMS): """ Convert a velocity in km/s to a wavelength shift based on the line center. Parameters: ----------- kms : float or array-like The velocity value(s) in kilometers per second. line_center : float The central (reference) wavelength of the spectral line. C_KMS : float, optional The speed of light in km/s. The default value is 2.99792458e5 km/s. Returns: -------- wl : float or array-like The calculated wavelength shift corresponding to the input velocity. """ wl = kms * line_center / C_KMS return wl
[docs] def wl_to_kms(wl, line_center, C_KMS=DEFAULT_C_KMS): """ Convert a velocity in km/s to a wavelength shift based on the line center. Parameters: ----------- wl : float or array-like The calculated wavelength shift corresponding to the input velocity. line_center : float The central (reference) wavelength of the spectral line. C_KMS : float, optional The speed of light in km/s. The default value is 2.99792458e5 km/s. Returns: -------- kms : float or array-like The velocity value(s) in kilometers per second. """ kms = (wl * C_KMS) / line_center return kms
[docs] def vac_to_air(lam_vac): """ Convert vacuum to air wavelengths :param lam_vac - Wavelength in Angstroms :return: lam_air - Wavelength in Angstroms """ lam = np.asarray(lam_vac) sigma2 = (1e4 / lam) ** 2 fact = 1 + 5.792105e-2 / (238.0185 - sigma2) + 1.67917e-3 / (57.362 - sigma2) return lam_vac / fact
def calc_flux(norm_amplitude, fwhm): r""" Compute the integrated flux of a Gaussian line profile. .. math:: F = A \cdot \mathrm{FWHM} \cdot \sqrt{ \frac{\pi}{4 \ln 2} } Parameters ---------- norm_amplitude : array-like Normalized amplitude of the Gaussian peak. fwhm : array-like Full width at half maximum in wavelength units. Returns ------- flux : jnp.ndarray Integrated line flux. """ return np.sqrt(2.0 * np.pi) * norm_amplitude * fwhm / (2.0 * np.sqrt(2.0 * np.log(2.0))) def calc_fwhm_kms(fwhm, C_KMS, center): r""" Convert FWHM in Å to velocity width in km/s. .. math:: v = \frac{\mathrm{FWHM}}{\lambda_0} \, C_KMS Parameters ---------- fwhm : float or array Full width at half maximum in Å. C_KMS : float Speed of light in km/s. center : float or array Line center wavelength in Å. Returns ------- v_kms : jnp.ndarray Velocity width in km/s. """ return (fwhm * C_KMS) / center def calc_luminosity(distance, flux): r""" Compute line luminosity from flux and luminosity distance. .. math:: L = 4 \pi D^2 \, F Parameters ---------- distance : float or array Luminosity distance in cm. flux : float or array Integrated line flux. Returns ------- luminosity : jnp.ndarray Line luminosity in erg/s. """ return 4.0 * np.pi * distance**2 * flux #* center def calc_monochromatic_luminosity(distance, flux_at_wavelength, wavelength): r""" Compute monochromatic luminosity at a given wavelength. .. math:: L_\lambda \cdot \lambda = \nu L_\nu = \lambda \, 4 \pi D^2 \, F_\lambda Parameters ---------- distance : float or array Luminosity distance in cm. flux_at_wavelength : float or array Flux density at the wavelength (erg/s/cm^2/Å). wavelength : float Wavelength in Å. Returns ------- L_lambda : jnp.ndarray Monochromatic luminosity in erg/s. """ return wavelength * 4.0 * np.pi * distance**2 * flux_at_wavelength def calc_bolometric_luminosity(monochromatic_lum, correction): r""" Apply a bolometric correction to a monochromatic luminosity. .. math:: L_{\mathrm{bol}} = L_\lambda \cdot C Parameters ---------- monochromatic_lum : float or array Monochromatic luminosity in erg/s. correction : float Bolometric correction factor. Returns ------- L_bol : jnp.ndarray Bolometric luminosity in erg/s. """ return monochromatic_lum * correction def calc_black_hole_mass(L_w, fwhm_kms, estimator): r""" Single-epoch BH mass estimator (continuum-based). .. math:: \log M_{\rm BH} = a + b \, (\log L - 44) + 2 \, \log \left(\frac{\mathrm{FWHM}}{1000}\right) .. math:: M_{\rm BH} = \frac{10^{\log M_{\rm BH}}}{f} Parameters ---------- L_w : float or array Monochromatic luminosity (erg/s). fwhm_kms : float or array Line width in km/s. estimator : dict Coefficients with keys ``a``, ``b``, ``f``. Returns ------- MBH : jnp.ndarray Black hole mass in solar masses. """ a, b, f = estimator["a"], estimator["b"], estimator["f"] log_L = log10(L_w) log_FWHM = log10(fwhm_kms) - 3 # FWHM in 1000 km/s log_M_BH = a + b * (log_L - 44.0) + 2.0 * log_FWHM return (10 ** log_M_BH) / f def calc_black_hole_mass_gh2015(L_halpha, fwhm_kms): r""" Greene & Ho (2015) Hα mass estimator (Eq. 6). .. math:: \log \left(\frac{M_{\rm BH}}{M_\odot}\right) = 6.57 + 0.47 \, (\log L_{H\alpha} - 42) + 2.06 \, \log \left(\frac{\mathrm{FWHM}}{1000}\right) Parameters ---------- L_halpha : float or array Hα line luminosity in erg/s. fwhm_kms : float or array FWHM in km/s. Returns ------- MBH : jnp.ndarray Black hole mass in solar masses. """ log_L = log10(L_halpha) log_FWHM = log10(fwhm_kms) - 3 log_M_BH = 6.57 + 0.47 * (log_L - 42.0) + 2.06 * log_FWHM return 10 ** log_M_BH