Dust Attenuation Curves

We implement a whole suite of different attenuation curves in synthesizer, including the following:

These attenuation curves can be instantiated directly, or attached to an EmissionModel to be used in the generation of complex spectra from a galaxy or galaxy component.

Each model has unique arguments required at instantiation, but all have the same base methods, such as get_transmission (which requires an optical depth (tau_v) and a wavelength array). Below, we show how to instantiate each of these models and plot their transmission and attenuation curves.

We first define a wavelength array up front:

[1]:
import numpy as np
from unyt import Angstrom

lams = np.logspace(3.1, 4, 1000) * Angstrom

PowerLaw

A PowerLaw only requires a slope to be defined. We can then use the in-built methods, e.g. get_transmission, to return the transmission over our wavelength array values.

[2]:
from synthesizer.emission_models.attenuation import PowerLaw

power_law = PowerLaw(-1.0)

pl_trans = power_law.get_transmission(0.33, lams)

Below we plot the transmission and attenuation curves.

[3]:
power_law.plot_transmission(0.33, lams, show=True)
power_law.plot_attenuation(lams, show=True)
../../_images/emission_models_attenuation_dust_attenuation_5_0.png
../../_images/emission_models_attenuation_dust_attenuation_5_1.png
[3]:
(<Figure size 800x600 with 1 Axes>,
 <Axes: xlabel='$\\lambda/(\\AA)$', ylabel='A$_{\\lambda}/$A$_{V}$'>)

Calzetti2000

The Calzetti2000 model requires a slope (slope), central wavelength of the UV bump (cent_lam), amplitude of the UV bump (ampl), and the FWHM of the UV bump (gamma). These default to 0.0, 0.2175 microns, 0, and 0.035, respectively. We plot the transmission curve both with the defaults and a non-zero bump amplitude.

[4]:
from synthesizer.emission_models.attenuation import Calzetti2000

no_bump = Calzetti2000()
with_bump = Calzetti2000(ampl=10.0)

fig, ax = no_bump.plot_attenuation(lams, show=False, label="No UV bump")
_, _ = with_bump.plot_attenuation(
    lams, fig=fig, ax=ax, show=True, label="With UV bump"
)
../../_images/emission_models_attenuation_dust_attenuation_7_0.png

MWN18

The MWN18 model loads a data file included with synthesizer; as such, it requires no arguments.

[5]:
from synthesizer.emission_models.attenuation import MWN18

mwn18 = MWN18()

_, _ = mwn18.plot_attenuation(lams, show=True)
../../_images/emission_models_attenuation_dust_attenuation_9_0.png

GrainsWD01

GrainsWD01 requires the model to be defined (either 'MW', 'LMC', or 'SMC'), and uses the dust_extinction module to load the appropriate model.

[6]:
from synthesizer.emission_models.attenuation import GrainsWD01

mw = GrainsWD01("MW")
smc = GrainsWD01("SMC")
lmc = GrainsWD01("LMC")

fig, ax = mw.plot_attenuation(lams, show=False, label="MW")
_, _ = smc.plot_attenuation(lams, fig=fig, ax=ax, show=False, label="SMC")
_, _ = lmc.plot_attenuation(lams, fig=fig, ax=ax, show=False, label="LMC")
ax.grid(ls="dotted", alpha=0.5)
../../_images/emission_models_attenuation_dust_attenuation_11_0.png

ParametricLi08

The ParametricLi08 model requires the UV slope (UV_slope, default 1.0), the optical to Near Infrared slope (OPT_NIR_slope, default 1.0), the Far UV slope (FUV_slope, default 1.0), and a dimensionless parameter between 0 and 1 controlling the strength of the UV bump (bump, default 0.0). Alternatively, a model string can be passed to adopt a preset model (possible values: "MW", "LMC", "SMC", or Calzetti).

[7]:
from synthesizer.emission_models.attenuation import ParametricLi08

mw_li08 = ParametricLi08(model="MW")
smc_li08 = ParametricLi08(model="SMC")
lmc_li08 = ParametricLi08(model="LMC")
calz_li08 = ParametricLi08(model="Calzetti")

fig, ax = mw_li08.plot_attenuation(lams, show=False, label="MW")
_, _ = smc_li08.plot_attenuation(lams, fig=fig, ax=ax, show=False, label="SMC")
_, _ = lmc_li08.plot_attenuation(lams, fig=fig, ax=ax, show=False, label="LMC")
_, _ = calz_li08.plot_attenuation(
    lams, fig=fig, ax=ax, show=False, label="Calzetti"
)
ax.grid(ls="dotted", alpha=0.5)
../../_images/emission_models_attenuation_dust_attenuation_13_0.png

Varying Attenuation Law Parameters

The parameters of an attenuation law (e.g. the slope of a PowerLaw) can be varied on-the-fly when calculating the attenuation or transmission curves. This allows us to instantiate a single attenuation law object, and then vary its parameters as needed, e.g. for generating a population of galaxies with different attenuation law slopes.

The way this works in practice is that we instantiate the attenuation law emission model as normal, but we override the parameters we want to vary with a string input, which will be the argument the code looks for on the emission model and emitter.

[8]:
from synthesizer.emission_models.attenuation import ParametricLi08

dust_curve = ParametricLi08(
    model="MW",
    OPT_NIR_slope="optical_slope",
    UV_slope="uv_slp",
    FUV_slope=None,
    bump="bump_ampl",
)

This emission model is not useable on its own, but when attached to a parent EmissionModel or emitter with the appropriate parameters, the parameters will be overridden on-the-fly when calculating the attenuation or transmission curves.

In the below example, we instantiate a ParametricLi08 attenuation law, but override the OPT_NIR_slope, UV_slope, and bump parameters with strings. When this attenuation law is attached to an emitter or emission model with these parameters, the values will be used instead of the defaults. If you set a parameter to None, it will expect an override with the same name as the parameter (e.g. FUV_slope in this case).

[9]:
from unyt import Msun, yr

from synthesizer.emission_models import TotalEmission
from synthesizer.grid import Grid
from synthesizer.parametric import Stars

grid = Grid("test_grid.hdf5")

stars = Stars(
    log10ages=grid.log10ages,
    metallicities=grid.log10metallicity,
    sf_hist=1e6 * yr,
    metal_dist=0.02,
    initial_mass=1e8 * Msun,
    optical_slope=-0.7,
    uv_slp=3.0,
    tau_v=1.0,
)

emergent = TotalEmission(
    grid=grid, dust_curve=dust_curve, bump_ampl=10, FUV_slope=2.0
)

stars.get_spectra(emergent)

stars.plot_spectra()
/home/runner/work/synthesizer/synthesizer/src/synthesizer/components/stellar.py:75: RuntimeWarning: invalid value encountered in log10
  self.log10metallicities = np.log10(
[9]:
(<Figure size 350x500 with 1 Axes>,
 <Axes: xlabel='$\\lambda/[\\mathrm{\\AA}]$', ylabel='$L_{\\nu}/[\\mathrm{\\rm{erg} \\ / \\ \\rm{Hz \\cdot \\rm{s}}}]$'>)
../../_images/emission_models_attenuation_dust_attenuation_17_2.png