"""A submodule containing the definition of the Unified AGN model.
This module contains the definition of the Unified AGN model that can be used
to generate spectra from components or as a foundation to work from when
creating more complex models.
Example usage::
# Create the Unified AGN model
model = UnifiedAGN(
nlr_grid=nlr_grid,
blr_grid=blr_grid,
covering_fraction_nlr=0.5,
covering_fraction_blr=0.5,
torus_emission_model=torus_emission_model,
)
# Generate a spectra
spectra = black_holes.get_spectra(model)
"""
from unyt import deg
from synthesizer import exceptions
from synthesizer.emission_models.base_model import BlackHoleEmissionModel
from synthesizer.emission_models.models import (
AttenuatedEmission,
DustEmission,
)
from synthesizer.emission_models.parameters import ParameterFunction
from synthesizer.emission_models.transformers import (
CoveringFraction,
DopplerBroadening,
EscapingFraction,
)
from synthesizer.exceptions import (
InconsistentParameter,
)
[docs]
def torus_edgeon_condition(inclination, theta_torus):
"""When this is > 90 deg the torus obscures the disc.
We will wrap this function in a ParameterFunction to use for masking
within the UnifiedAGN model.
Args:
inclination (unyt_array):
The inclination of the black hole.
theta_torus (unyt_array):
The torus opening angle.
"""
return inclination + theta_torus
# Wrap the torus_edgeon_condition in a ParameterFunction
torus_edgeon_handler = ParameterFunction(
func=torus_edgeon_condition,
sets="torus_edgeon_cond",
func_args=("inclination", "theta_torus"),
)
[docs]
class UnifiedAGNIntrinsic(BlackHoleEmissionModel):
"""An emission model that defines the Unified AGN model with no dust.
The UnifiedAGN model includes a disc, nlr, blr and torus component and
combines these components taking into account geometry of the disc
and torus. This model does not include diffuse dust emission.
Attributes:
disc_incident_isotropic (BlackHoleEmissionModel):
The disc emission model assuming isotropic emission.
disc_incident (BlackHoleEmissionModel):
The disc emission model accounting for the geometry but unmasked.
disc_averaged (BlackHoleEmissionModel):
The inclination averaged observed disc emission.
disc_averaged_without_torus (BlackHoleEmissionModel):
The inclination averaged observed disc ignoring the torus.
disc_transmitted_nlr (BlackHoleEmissionModel):
The disc spectrum transmitted through the NLR
disc_transmitted_blr (BlackHoleEmissionModel):
The disc spectrum transmitted through the BLR
disc_transmitted (BlackHoleEmissionModel):
The disc transmitted emission
disc_transmitted_weighted_combination (BlackHoleEmissionModel):
The disc transmitted weighted combination emission
disc (BlackHoleEmissionModel):
The disc emission model
nlr (BlackHoleEmissionModel):
The NLR emission model
blr (BlackHoleEmissionModel):
The BLR emission model
line_regions (BlackHoleEmissionModel):
The combined BLR and NLR emission
nlr_continuum (BlackHoleEmissionModel):
The NLR continuum emission
blr_continuum (BlackHoleEmissionModel):
The BLR continuum emission
torus (BlackHoleEmissionModel):
The torus emission model
"""
def __init__(
self,
nlr_grid,
blr_grid,
torus_emission_model,
disc_transmission="weighted_combination",
velocity_dispersion_blr=None,
velocity_dispersion_nlr=None,
label="intrinsic",
**kwargs,
):
"""Initialize the UnifiedAGN model.
Args:
nlr_grid (synthesizer.grid.Grid):
The grid for the NLR.
blr_grid (synthesizer.grid.Grid):
The grid for the BLR.
torus_emission_model (synthesizer.dust.EmissionModel):
The dust emission model to use for the torus.
disc_transmission (str):
How the observed disc spectrum is constructed. Options are:
``"weighted_combination"`` (default), which combines the
unobscured, NLR-transmitted, and BLR-transmitted disc spectra
using ``transmission_fraction_escape``,
``transmission_fraction_nlr``, and
``transmission_fraction_blr`` on the black hole component;
``"random"``, which uses the precomputed
``random_transmission_fraction_*`` attributes on the black hole
component; ``"none"`` or
``"escaped"``, which uses only the unobscured disc emission;
``"nlr"``, which uses only disc emission transmitted through
the NLR; and ``"blr"``, which uses only disc emission
transmitted through the BLR.
velocity_dispersion_blr (unyt_quantity):
The optional velocity dispersion to use when Doppler broadening
the final BLR emission. If ``None`` no broadening is applied.
velocity_dispersion_nlr (unyt_quantity):
The optional velocity dispersion to use when Doppler broadening
the final NLR emission. If ``None`` no broadening is applied.
label (str):
The label for the resulting spectra. Defaults to "intrinsic".
**kwargs: Any additional keyword arguments to pass to the
BlackHoleEmissionModel.
"""
# Check that certain parameters are not provided as they would produce
# inconsistent results.
for arg_to_check in ["inclination", "theta_torus"]:
if arg_to_check in kwargs.keys():
raise exceptions.InconsistentArguments(
f"{arg_to_check} must be set on the blackhole object, "
"not passed as a keyword argument to the emission model."
)
# Get the incident isotropic disc emission model
self.disc_incident_isotropic = self._make_disc_incident_isotropic(
nlr_grid,
**kwargs,
)
# Get the incident disc emission model
self.disc_incident, self.disc_incident_masked = (
self._make_disc_incident(
nlr_grid,
**kwargs,
)
)
# Get the emission transmitted through the BLR and NLR
(
self.disc_transmitted_nlr_full,
self.disc_transmitted_blr_full,
self.disc_transmitted_nlr_isotropic_full,
self.disc_transmitted_blr_isotropic_full,
) = self._make_disc_transmitted_lr_full(
nlr_grid,
blr_grid,
**kwargs,
)
# Get the averaged disc spectrum with and without the torus
(
self.disc_averaged,
self.disc_averaged_without_torus,
) = self._make_disc_averaged(
**kwargs,
)
# Get the weighted_combination transmitted disc spectrum
self.disc_transmitted_weighted_combination = (
self._make_disc_transmitted_weighted_combination(
**kwargs,
)
)
# Get the transmitted disc emission spectrum
self.disc_transmitted = self._make_disc_transmitted(
disc_transmission,
**kwargs,
)
# Create the disc spectrum
self.disc = self._make_disc(**kwargs)
# Get the line region spectra
self.nlr, self.nlr_continuum, self.blr, self.blr_continuum = (
self._make_line_regions(
nlr_grid,
blr_grid,
velocity_dispersion_blr=velocity_dispersion_blr,
velocity_dispersion_nlr=velocity_dispersion_nlr,
**kwargs,
)
)
# Combined line region spectrum.
self.line_regions = BlackHoleEmissionModel(
label="line_regions",
combine=(
self.nlr,
self.blr,
),
**kwargs,
)
# Get the torus emission model
self.torus = self._make_torus(torus_emission_model, **kwargs)
return BlackHoleEmissionModel.__init__(
self,
label=label,
combine=(
self.disc,
self.nlr,
self.blr,
self.torus,
),
related_models=(
self.disc_incident_isotropic,
self.disc_incident,
self.disc_averaged,
self.disc_averaged_without_torus,
self.disc_transmitted,
self.disc_transmitted_weighted_combination,
self.disc,
self.line_regions,
self.nlr_continuum,
self.blr_continuum,
),
**kwargs,
)
def _make_disc_incident_isotropic(self, grid, **kwargs):
"""Make the disc spectra assuming isotropic emission."""
model = BlackHoleEmissionModel(
grid=grid,
label="disc_incident_isotropic",
extract="incident",
cosine_inclination=0.5,
hydrogen_density="hydrogen_density_blr",
ionisation_parameter="ionisation_parameter_blr",
**kwargs,
)
return model
def _make_disc_incident(
self,
grid,
**kwargs,
):
"""Make the disc spectra."""
# unmasked
disc_incident = BlackHoleEmissionModel(
grid=grid,
label="disc_incident",
extract="incident",
hydrogen_density="hydrogen_density_blr",
ionisation_parameter="ionisation_parameter_blr",
**kwargs,
)
# masked for the torus
disc_incident_masked = BlackHoleEmissionModel(
grid=grid,
label="disc_incident_masked",
extract="incident",
hydrogen_density="hydrogen_density_blr",
ionisation_parameter="ionisation_parameter_blr",
mask_attr="torus_edgeon_cond",
torus_edgeon_cond=torus_edgeon_handler,
mask_thresh=90 * deg,
mask_op="<",
**kwargs,
)
return disc_incident, disc_incident_masked
def _make_disc_transmitted_lr_full(
self,
nlr_grid,
blr_grid,
**kwargs,
):
"""Calculate the disc spectrum transmitted through the line regions.
Args:
nlr_grid (synthesizer.grid.Grid):
The grid for the NLR.
blr_grid (synthesizer.grid.Grid):
The grid for the BLR.
**kwargs: Any additional keyword arguments to pass to the
BlackHoleEmissionModel.
"""
# Calculate the "full" spectrum transmitted through the line regions.
# This masks for the torus but does not yet include the covering
# fraction.
disc_transmitted_nlr_full = BlackHoleEmissionModel(
grid=nlr_grid,
label="disc_transmitted_nlr_full",
extract="transmitted",
hydrogen_density="hydrogen_density_nlr",
ionisation_parameter="ionisation_parameter_nlr",
mask_attr="torus_edgeon_cond",
torus_edgeon_cond=torus_edgeon_handler,
mask_thresh=90 * deg,
mask_op="<",
**kwargs,
)
disc_transmitted_blr_full = BlackHoleEmissionModel(
grid=blr_grid,
label="disc_transmitted_blr_full",
extract="transmitted",
hydrogen_density="hydrogen_density_blr",
ionisation_parameter="ionisation_parameter_blr",
mask_attr="torus_edgeon_cond",
torus_edgeon_cond=torus_edgeon_handler,
mask_thresh=90 * deg,
mask_op="<",
**kwargs,
)
# Calculate the istropic spectrum transmitted through each of the line
# regions. This does not include masking of the spectrum.
disc_transmitted_nlr_isotropic_full = BlackHoleEmissionModel(
grid=nlr_grid,
label="disc_transmitted_nlr_isotropic_full",
extract="transmitted",
cosine_inclination=0.5,
hydrogen_density="hydrogen_density_nlr",
ionisation_parameter="ionisation_parameter_nlr",
**kwargs,
)
disc_transmitted_blr_isotropic_full = BlackHoleEmissionModel(
grid=blr_grid,
label="disc_transmitted_blr_isotropic_full",
extract="transmitted",
cosine_inclination=0.5,
hydrogen_density="hydrogen_density_blr",
ionisation_parameter="ionisation_parameter_blr",
**kwargs,
)
return (
disc_transmitted_nlr_full,
disc_transmitted_blr_full,
disc_transmitted_nlr_isotropic_full,
disc_transmitted_blr_isotropic_full,
)
def _make_disc_transmitted_weighted_combination(
self,
**kwargs,
):
"""Calculate the weighted_combination disc spectrum.
Note: when the viewing angle (inlination) meets the torus criteria
it is always blocked.
"""
# Now calculate the disc_escaped emission using this transmission
# fraction.
disc_escaped_weighted = BlackHoleEmissionModel(
label="disc_escaped",
apply_to=self.disc_incident_masked,
transformer=CoveringFraction(
covering_attrs=("transmission_fraction_escape",)
),
**kwargs,
)
# Now calculate the disc_transmitted_nlr emission using this
# transmission fraction.
disc_transmitted_nlr_weighted = BlackHoleEmissionModel(
label="disc_transmitted_nlr",
apply_to=self.disc_transmitted_nlr_full,
transformer=CoveringFraction(
covering_attrs=("transmission_fraction_nlr",)
),
**kwargs,
)
# Now calculate the disc_transmitted_blr emission using this
# transmission fraction.
disc_transmitted_blr_weighted = BlackHoleEmissionModel(
label="disc_transmitted_blr",
apply_to=self.disc_transmitted_blr_full,
transformer=CoveringFraction(
covering_attrs=("transmission_fraction_blr",)
),
**kwargs,
)
# Now combine the three different components to produce the total.
disc_transmitted_averaged = BlackHoleEmissionModel(
label="disc_transmitted_weighted_combination",
combine=(
disc_escaped_weighted,
disc_transmitted_nlr_weighted,
disc_transmitted_blr_weighted,
),
**kwargs,
)
return disc_transmitted_averaged
def _make_disc_transmitted(
self,
disc_transmission,
**kwargs,
):
"""Calculate the observed disc spectrum.
For an individual blackhole there are four options. Either the disc
emission escapes (disc_transmission='none'), is transmitted through
the NLR (disc_transmission='nlr'), is transmitted through the BLR
(disc_transmission='blr'), or is the weighted combination
(disc_transmission='weighted_combination').
The ``disc_transmission`` argument controls which of these sightline
treatments is used. ``"weighted_combination"`` uses the deterministic
transmission fractions on the component to produce the average
transmitted disc spectrum and is the default. ``"random"`` uses
precomputed
``random_transmission_fraction_*`` attributes on the black hole
component. ``"none"``/``"escaped"``, ``"nlr"``, and ``"blr"`` force
all black holes onto a single transmission path.
Note: when the viewing angle (inlination) meets the torus criteria
it is always blocked.
Args:
disc_transmission (str):
Which transmission scenario to use for the observed disc
spectrum. ``"weighted_combination"`` uses
``transmission_fraction_escape``,
``transmission_fraction_nlr``, and
``transmission_fraction_blr`` on the component and returns the
average over unobscured, NLR-transmitted, and BLR-transmitted
sightlines.
``"random"`` uses the precomputed
``random_transmission_fraction_*`` attributes on the black hole
component. ``"none"`` or
``"escaped"`` uses only unobscured disc emission,
``"nlr"`` uses only NLR-transmitted disc emission, and
``"blr"`` uses only BLR-transmitted disc emission.
**kwargs: Any additional keyword arguments to pass to the
BlackHoleEmissionModel.
"""
if disc_transmission in ["escaped", "none", "nlr", "blr", "random"]:
# If disc_transmission == 'none' the emission seen by the observer
# is simply the incident emission. This step also accounts for the
# torus.
if disc_transmission in ["none", "escaped"]:
transmission_fraction_escape = 1.0
transmission_fraction_nlr = 0.0
transmission_fraction_blr = 0.0
# If disc_transmission == 'nlr' the emission seen by the observer
# is the spectrum transmitted through the NLR. This step also
# accounts for the torus.
elif disc_transmission == "nlr":
transmission_fraction_escape = 0.0
transmission_fraction_nlr = 1.0
transmission_fraction_blr = 0.0
# If disc_transmission == 'blr' the emission seen by the observer
# is the spectrum transmitted through the BLR. This step also
# accounts for the torus.
elif disc_transmission == "blr":
transmission_fraction_escape = 0.0
transmission_fraction_nlr = 0.0
transmission_fraction_blr = 1.0
# If disc_transmission == 'random' the emission seen by the
# observer is chosen at random for each blackhole using covering
# fractions. This is only possible if the transmission fractions
# have been set on the component.
elif disc_transmission == "random":
transmission_fraction_escape = (
"random_transmission_fraction_escape"
)
transmission_fraction_nlr = "random_transmission_fraction_nlr"
transmission_fraction_blr = "random_transmission_fraction_blr"
# Now calculate the disc_escaped emission using this transmission
# fraction.
self.disc_escaped = BlackHoleEmissionModel(
label="disc_escaped_selected",
apply_to=self.disc_incident_masked,
transformer=CoveringFraction(
covering_attrs=("transmission_fraction_escape",)
),
transmission_fraction_escape=transmission_fraction_escape,
**kwargs,
)
# Now calculate the disc_transmitted_nlr emission using this
# transmission fraction.
self.disc_transmitted_nlr = BlackHoleEmissionModel(
label="disc_transmitted_nlr_selected",
apply_to=self.disc_transmitted_nlr_full,
transformer=CoveringFraction(
covering_attrs=("transmission_fraction_nlr",)
),
transmission_fraction_nlr=transmission_fraction_nlr,
**kwargs,
)
# Now calculate the disc_transmitted_blr emission using this
# transmission fraction.
self.disc_transmitted_blr = BlackHoleEmissionModel(
label="disc_transmitted_blr_selected",
apply_to=self.disc_transmitted_blr_full,
transformer=CoveringFraction(
covering_attrs=("transmission_fraction_blr",)
),
transmission_fraction_blr=transmission_fraction_blr,
**kwargs,
)
# Now combine the three different components to produce the total.
disc_transmitted = BlackHoleEmissionModel(
label="disc_transmitted",
combine=(
self.disc_escaped,
self.disc_transmitted_nlr,
self.disc_transmitted_blr,
),
**kwargs,
)
# If weighted_combination is selected the transmitted is simply the
# combination of the three scenarios weighted by the respective
# covering fractions.
elif disc_transmission == "weighted_combination":
disc_transmitted = BlackHoleEmissionModel(
label="disc_transmitted",
combine=(self.disc_transmitted_weighted_combination,),
**kwargs,
)
# Otherwise raise exception.
else:
raise InconsistentParameter("disc_transmission not recognised")
return disc_transmitted
def _make_disc(self, **kwargs):
"""Now is effectively just an alias to disc_transmitted."""
return BlackHoleEmissionModel(
label="disc",
combine=(self.disc_transmitted,),
**kwargs,
)
def _make_disc_averaged(
self,
**kwargs,
):
"""Calculate the isotropic (inclination averaged) disc spectrum."""
# Calculate the total amount of disc emission which escapes the BLR
# and NLR, ignoring the torus
disc_escaped_isotropic = BlackHoleEmissionModel(
label="disc_escaped_isotropic",
apply_to=self.disc_incident_isotropic,
transformer=EscapingFraction(
covering_attrs=(
"covering_fraction_blr",
"covering_fraction_nlr",
)
),
**kwargs,
)
# Calculate the total amount of disc emission which is transmitted
# through the NLR ignoring the torus
disc_transmitted_nlr_isotropic = BlackHoleEmissionModel(
label="disc_transmitted_nlr_isotropic",
apply_to=self.disc_transmitted_nlr_isotropic_full,
transformer=CoveringFraction(
covering_attrs=("covering_fraction_nlr",)
),
**kwargs,
)
# Calculate the total amount of disc emission which is transmitted
# through the BLR ignoring the torus
disc_transmitted_blr_isotropic = BlackHoleEmissionModel(
label="disc_transmitted_blr_isotropic",
apply_to=self.disc_transmitted_blr_isotropic_full,
transformer=CoveringFraction(
covering_attrs=("covering_fraction_blr",)
),
**kwargs,
)
# Combine these three
disc_averaged_without_torus = BlackHoleEmissionModel(
label="disc_averaged_without_torus",
combine=(
disc_escaped_isotropic,
disc_transmitted_nlr_isotropic,
disc_transmitted_blr_isotropic,
),
**kwargs,
)
# Now adjust for the torus. This is essentially the averaged light
# received from the disc.
disc_averaged = BlackHoleEmissionModel(
label="disc_averaged",
apply_to=disc_averaged_without_torus,
transformer=EscapingFraction(covering_attrs=("torus_fraction",)),
**kwargs,
)
return disc_averaged, disc_averaged_without_torus
def _make_line_regions(
self,
nlr_grid,
blr_grid,
velocity_dispersion_blr=None,
velocity_dispersion_nlr=None,
**kwargs,
):
"""Make the line regions.
These use the nebular spectra in the relevant grids but utilise the
isotropic emission (cosine_inclination=0.5) instead of taking account
of the observer inclination since the BLR are illuminated by a wider
range of lines-of-sight.
"""
# Extract the NLR spectra from the grid. Here cosine_inclination=0.5
# because we are using the isotropic disc emission. No masking is
# applied for the NLR because it always assumed to be visible.
full_nlr = BlackHoleEmissionModel(
grid=nlr_grid,
label="full_reprocessed_nlr",
extract="nebular",
cosine_inclination=0.5,
hydrogen_density="hydrogen_density_nlr",
ionisation_parameter="ionisation_parameter_nlr",
**kwargs,
)
# Extract the BLR spectra from the grid. Here cosine_inclination=0.5
# because we are using the isotropic disc emission. Masking is
# applied for the BLR because it assumed to be blocked by the torus.
full_blr = BlackHoleEmissionModel(
grid=blr_grid,
label="full_reprocessed_blr",
extract="nebular",
mask_attr="torus_edgeon_cond",
torus_edgeon_cond=torus_edgeon_handler,
mask_thresh=90 * deg,
mask_op="<",
cosine_inclination=0.5,
hydrogen_density="hydrogen_density_blr",
ionisation_parameter="ionisation_parameter_blr",
**kwargs,
)
# As above but for the continuum emission alone
full_nlr_continuum = BlackHoleEmissionModel(
grid=nlr_grid,
label="full_continuum_nlr",
extract="nebular_continuum",
cosine_inclination=0.5,
hydrogen_density="hydrogen_density_nlr",
ionisation_parameter="ionisation_parameter_nlr",
**kwargs,
)
full_blr_continuum = BlackHoleEmissionModel(
grid=blr_grid,
label="full_continuum_blr",
extract="nebular_continuum",
mask_attr="torus_edgeon_cond",
torus_edgeon_cond=torus_edgeon_handler,
mask_thresh=90 * deg,
mask_op="<",
cosine_inclination=0.5,
hydrogen_density="hydrogen_density_blr",
ionisation_parameter="ionisation_parameter_blr",
**kwargs,
)
# Now apply the relevant covering fractions to the different spectra
nlr_label = (
"unbroadened_nlr" if velocity_dispersion_nlr is not None else "nlr"
)
blr_label = (
"unbroadened_blr" if velocity_dispersion_blr is not None else "blr"
)
nlr = BlackHoleEmissionModel(
label=nlr_label,
apply_to=full_nlr,
transformer=CoveringFraction(
covering_attrs=("covering_fraction_nlr",)
),
**kwargs,
)
blr = BlackHoleEmissionModel(
label=blr_label,
apply_to=full_blr,
transformer=CoveringFraction(
covering_attrs=("covering_fraction_blr",)
),
**kwargs,
)
nlr_continuum = BlackHoleEmissionModel(
label="nlr_continuum",
apply_to=full_nlr_continuum,
transformer=CoveringFraction(
covering_attrs=("covering_fraction_nlr",)
),
**kwargs,
)
blr_continuum = BlackHoleEmissionModel(
label="blr_continuum",
apply_to=full_blr_continuum,
transformer=CoveringFraction(
covering_attrs=("covering_fraction_blr",)
),
**kwargs,
)
if velocity_dispersion_nlr is not None:
nlr = BlackHoleEmissionModel(
label="nlr",
apply_to=nlr,
transformer=DopplerBroadening(
sigma_v_attr="velocity_dispersion_nlr"
),
velocity_dispersion_nlr=velocity_dispersion_nlr,
**kwargs,
)
if velocity_dispersion_blr is not None:
blr = BlackHoleEmissionModel(
label="blr",
apply_to=blr,
transformer=DopplerBroadening(
sigma_v_attr="velocity_dispersion_blr"
),
velocity_dispersion_blr=velocity_dispersion_blr,
**kwargs,
)
return nlr, nlr_continuum, blr, blr_continuum
def _make_torus(self, torus_emission_model, **kwargs):
"""Make the torus spectra."""
torus_emission_model.set_scaler(self.disc_incident_isotropic)
return BlackHoleEmissionModel(
label="torus",
generator=torus_emission_model,
scale_by="torus_fraction",
**kwargs,
)
[docs]
class UnifiedAGNWithDiffuseDustAttenuation(BlackHoleEmissionModel):
"""An emission model that defines the Unified AGN model.
The UnifiedAGN model includes a disc, nlr, blr and torus component and
combines these components taking into account geometry of the disc
and torus. This variant includes dust attenuation.
Attributes:
intrinsic (BlackHoleEmissionModel):
The intrinsic emission
"""
def __init__(
self,
nlr_grid,
blr_grid,
torus_emission_model,
diffuse_dust_curve,
disc_transmission="weighted_combination",
velocity_dispersion_blr=None,
velocity_dispersion_nlr=None,
label="attenuated",
tau_v="tau_v",
**kwargs,
):
"""Initialize the UnifiedAGN model.
Args:
nlr_grid (synthesizer.grid.Grid):
The grid for the NLR.
blr_grid (synthesizer.grid.Grid):
The grid for the BLR.
torus_emission_model (synthesizer.dust.EmissionModel):
The dust emission model to use for the torus.
diffuse_dust_curve (synthesizer.emission_models.attenuation):
The dust attenuation curve for diffuse dust.
disc_transmission (str):
How the observed disc spectrum is constructed. Options are:
``"weighted_combination"`` (default), which combines the
unobscured, NLR-transmitted, and BLR-transmitted disc spectra
using ``transmission_fraction_escape``,
``transmission_fraction_nlr``, and
``transmission_fraction_blr`` on the black hole component;
``"random"``, which uses the precomputed
``random_transmission_fraction_*``
attributes on the black hole component; ``"none"`` or
``"escaped"``, which uses only
the unobscured disc emission; ``"nlr"``, which uses only
disc emission transmitted through the NLR; and ``"blr"``,
which uses only disc emission transmitted through the BLR.
velocity_dispersion_blr (unyt_quantity):
The optional velocity dispersion to use when Doppler broadening
the final BLR emission. If ``None`` no broadening is applied.
velocity_dispersion_nlr (unyt_quantity):
The optional velocity dispersion to use when Doppler broadening
the final NLR emission. If ``None`` no broadening is applied.
label (str):
The label for the resulting spectra. This defaults to
"attenuated".
tau_v (str):
The attribute on the emitter to use for tau_v
**kwargs: Any additional keyword arguments to pass to the
BlackHoleEmissionModel.
"""
# Calculate the intrinsic emission
self.intrinsic = UnifiedAGNIntrinsic(
nlr_grid,
blr_grid,
torus_emission_model,
disc_transmission=disc_transmission,
velocity_dispersion_blr=velocity_dispersion_blr,
velocity_dispersion_nlr=velocity_dispersion_nlr,
**kwargs,
)
# Include attenuation from diffuse dust
AttenuatedEmission.__init__(
self,
dust_curve=diffuse_dust_curve,
apply_to=self.intrinsic,
tau_v=tau_v,
emitter="blackhole",
label=label,
**kwargs,
)
[docs]
class UnifiedAGNWithDiffuseDustAttenuationAndEmission(BlackHoleEmissionModel):
"""An emission model that defines the Unified AGN model.
The UnifiedAGN model includes a disc, nlr, blr and torus component and
combines these components taking into account geometry of the disc
and torus. This variant includes dust attenuation and emission.
Attributes:
intrinsic (BlackHoleEmissionModel):
The intrinsic emission
attenuated (BlackHoleEmissionModel):
The attenuated emission
diffuse_dust_emission (BlackHoleEmissionModel):
The diffuse dust emission
"""
def __init__(
self,
nlr_grid,
blr_grid,
torus_emission_model,
diffuse_dust_curve,
diffuse_dust_emission_model,
tau_v="tau_v",
disc_transmission="weighted_combination",
velocity_dispersion_blr=None,
velocity_dispersion_nlr=None,
label="total",
**kwargs,
):
"""Initialize the UnifiedAGN model.
Args:
nlr_grid (synthesizer.grid.Grid):
The grid for the NLR.
blr_grid (synthesizer.grid.Grid):
The grid for the BLR.
torus_emission_model (synthesizer.dust.EmissionModel):
The dust emission model to use for the torus.
disc_transmission (str):
How the observed disc spectrum is constructed. Options are:
``"weighted_combination"`` (default), which combines the
unobscured, NLR-transmitted, and BLR-transmitted disc spectra
using ``transmission_fraction_escape``,
``transmission_fraction_nlr``, and
``transmission_fraction_blr`` on the black hole component;
``"random"``, which uses the precomputed
``random_transmission_fraction_*``
attributes on the black hole component; ``"none"`` or
``"escaped"``, which uses only
the unobscured disc emission; ``"nlr"``, which uses only
disc emission transmitted through the NLR; and ``"blr"``,
which uses only disc emission transmitted through the BLR.
diffuse_dust_curve (synthesizer.emission_models.attenuation):
The dust attenuation curve for diffuse dust.
diffuse_dust_emission_model:
The diffuse dust emission model.
velocity_dispersion_blr (unyt_quantity):
The optional velocity dispersion to use when Doppler broadening
the final BLR emission. If ``None`` no broadening is applied.
velocity_dispersion_nlr (unyt_quantity):
The optional velocity dispersion to use when Doppler broadening
the final NLR emission. If ``None`` no broadening is applied.
tau_v (str):
The attribute on the emitter to use for tau_v
label (str):
The label for the resulting spectra. When dust attenuation and
emission is included this defaults to "total" otherwise it
defaults to "intrinsic".
**kwargs: Any additional keyword arguments to pass to the
BlackHoleEmissionModel.
"""
# Calculate the intrinsic emission
self.intrinsic = UnifiedAGNIntrinsic(
nlr_grid,
blr_grid,
torus_emission_model,
disc_transmission=disc_transmission,
velocity_dispersion_blr=velocity_dispersion_blr,
velocity_dispersion_nlr=velocity_dispersion_nlr,
**kwargs,
)
# Include attenuation from diffuse dust
self.attenuated = AttenuatedEmission(
dust_curve=diffuse_dust_curve,
apply_to=self.intrinsic,
tau_v=tau_v,
emitter="blackhole",
label="attenuated",
**kwargs,
)
# Add diffuse dust emission
self.diffuse_dust_emission = DustEmission(
dust_emission_model=diffuse_dust_emission_model,
dust_lum_intrinsic=self.intrinsic,
dust_lum_attenuated=self.attenuated,
emitter="blackhole",
label="diffuse_dust_emission",
**kwargs,
)
# Finally make the total model, this is attenuated +
# diffuse_dust_emission
BlackHoleEmissionModel.__init__(
self,
label=label,
combine=(self.attenuated, self.diffuse_dust_emission),
related_models=(
self.intrinsic,
self.attenuated,
self.diffuse_dust_emission,
),
**kwargs,
)
[docs]
class UnifiedAGN(BlackHoleEmissionModel):
"""An emission model that defines the Unified AGN model.
The UnifiedAGN model includes a disc, nlr, blr and torus component and
combines these components taking into account geometry of the disc
and torus. This variant includes dust attenuation.
"""
def __new__(
cls,
nlr_grid,
blr_grid,
torus_emission_model,
disc_transmission="weighted_combination",
diffuse_dust_curve=None,
diffuse_dust_emission_model=None,
velocity_dispersion_blr=None,
velocity_dispersion_nlr=None,
label=None,
**kwargs,
):
"""Initialize the UnifiedAGN model.
Args:
nlr_grid (synthesizer.grid.Grid):
The grid for the NLR.
blr_grid (synthesizer.grid.Grid):
The grid for the BLR.
torus_emission_model (synthesizer.dust.EmissionModel):
The dust emission model to use for the torus.
disc_transmission (str):
How the observed disc spectrum is constructed. Options are:
``"weighted_combination"`` (default), which combines the
unobscured, NLR-transmitted, and BLR-transmitted disc spectra
using ``transmission_fraction_escape``,
``transmission_fraction_nlr``, and
``transmission_fraction_blr`` on the black hole component;
``"random"``, which uses the precomputed
``random_transmission_fraction_*``
attributes on the black hole component; ``"none"`` or
``"escaped"``, which uses only
the unobscured disc emission; ``"nlr"``, which uses only
disc emission transmitted through the NLR; and ``"blr"``,
which uses only disc emission transmitted through the BLR.
diffuse_dust_curve (synthesizer.emission_models.attenuation):
The dust attenuation curve for diffuse dust.
diffuse_dust_emission_model:
The diffuse dust emission model.
velocity_dispersion_blr (unyt_quantity):
The optional velocity dispersion to use when Doppler broadening
the final BLR emission. If ``None`` no broadening is applied.
velocity_dispersion_nlr (unyt_quantity):
The optional velocity dispersion to use when Doppler broadening
the final NLR emission. If ``None`` no broadening is applied.
label (str):
The label for the resulting spectra. When dust attenuation and
emission is included this defaults to "total" otherwise it
defaults to "intrinsic".
**kwargs: Any additional keyword arguments to pass to the
BlackHoleEmissionModel.
"""
# Validate that dust emission model is not provided without a curve
if diffuse_dust_emission_model and not diffuse_dust_curve:
raise exceptions.InconsistentArguments(
"diffuse_dust_emission_model requires diffuse_dust_curve to "
"be specified."
)
# If diffuse_dust_curve and diffuse_dust_emission_model provided then
# include these
if diffuse_dust_curve and diffuse_dust_emission_model:
if label is None:
label = "total"
return UnifiedAGNWithDiffuseDustAttenuationAndEmission(
nlr_grid,
blr_grid,
torus_emission_model,
diffuse_dust_curve,
diffuse_dust_emission_model,
disc_transmission=disc_transmission,
velocity_dispersion_blr=velocity_dispersion_blr,
velocity_dispersion_nlr=velocity_dispersion_nlr,
label=label,
**kwargs,
)
# Otherwise if only the diffuse_dust_curve is provided:
elif diffuse_dust_curve:
if label is None:
label = "attenuated"
return UnifiedAGNWithDiffuseDustAttenuation(
nlr_grid,
blr_grid,
torus_emission_model,
diffuse_dust_curve,
disc_transmission=disc_transmission,
velocity_dispersion_blr=velocity_dispersion_blr,
velocity_dispersion_nlr=velocity_dispersion_nlr,
label=label,
**kwargs,
)
# Otherwise return the intrinsic emission
else:
if label is None:
label = "intrinsic"
return UnifiedAGNIntrinsic(
nlr_grid,
blr_grid,
torus_emission_model,
disc_transmission=disc_transmission,
velocity_dispersion_blr=velocity_dispersion_blr,
velocity_dispersion_nlr=velocity_dispersion_nlr,
label=label,
**kwargs,
)