Blackholes

Synthesizer has a collection of routines for modelling the emission of black holes (i.e. AGN). When coupled with a Galaxy object it also allows users to combine with the emission from other galaxy components (i.e. stellar emission).

Unlike stellar emission the division between a particle and a parametric BlackHoles/BlackHole object is not well defined; we explain below the differences in different use cases.

Parametric Blackholes

If you are only interested in exploring the parameter space of AGN emission without simulation data to forward model you can use a parametric.BlackHole. There are some specific differences compared to particle.BlackHole objects to keep in mind:

  • A parametric.BlackHole can only ever describe a singular black hole.

  • A parametric.BlackHole’s “position” (i.e. if making an image) is described by a PointSource morphology object rather than coordinates.

  • A parametric.BlackHole exists in isolation, i.e. it does not interface directly with other parametric components.

[1]:
import numpy as np
from unyt import Mpc, Msun, cm, deg, ly, yr

from synthesizer import galaxy
from synthesizer.parametric import BlackHole

# Set a random number seed to ensure consistent results
np.random.seed(42)

First we need to initialise our BlackHole object with the parameters that will be needed to compute spectra.

[2]:
blackhole = BlackHole(
    mass=1e8 * Msun,
    inclination=60 * deg,
    accretion_rate=1 * Msun / yr,
    metallicity=0.01,
)

Like other synthesizer objects we can get more information using the print command.

[3]:
print(blackhole)
+---------------------------------------------------------------------------------------------------------+
|                                               BLACK HOLES                                               |
+------------------------------+--------------------------------------------------------------------------+
| Attribute                    | Value                                                                    |
+------------------------------+--------------------------------------------------------------------------+
| component_type               | 'BlackHoles'                                                             |
+------------------------------+--------------------------------------------------------------------------+
| fesc                         | 0.00e+00                                                                 |
+------------------------------+--------------------------------------------------------------------------+
| epsilon                      | 0.10                                                                     |
+------------------------------+--------------------------------------------------------------------------+
| accretion_rate_eddington     | 1.72e+33                                                                 |
+------------------------------+--------------------------------------------------------------------------+
| metallicity                  | 0.01                                                                     |
+------------------------------+--------------------------------------------------------------------------+
| ionisation_parameter_blr     | 0.10                                                                     |
+------------------------------+--------------------------------------------------------------------------+
| covering_fraction_blr        | 0.10                                                                     |
+------------------------------+--------------------------------------------------------------------------+
| ionisation_parameter_nlr     | 0.01                                                                     |
+------------------------------+--------------------------------------------------------------------------+
| covering_fraction_nlr        | 0.10                                                                     |
+------------------------------+--------------------------------------------------------------------------+
| covering_fraction            | 0.20                                                                     |
+------------------------------+--------------------------------------------------------------------------+
| escape_fraction              | 0.80                                                                     |
+------------------------------+--------------------------------------------------------------------------+
| transmission_fraction_escape | 1.00                                                                     |
+------------------------------+--------------------------------------------------------------------------+
| transmission_fraction_nlr    | 0.00e+00                                                                 |
+------------------------------+--------------------------------------------------------------------------+
| transmission_fraction_blr    | 0.00e+00                                                                 |
+------------------------------+--------------------------------------------------------------------------+
| disc_transmission            | 'none'                                                                   |
+------------------------------+--------------------------------------------------------------------------+
| eddington_ratio              | 0.45                                                                     |
+------------------------------+--------------------------------------------------------------------------+
| cosine_inclination           | 0.50                                                                     |
+------------------------------+--------------------------------------------------------------------------+
| nparticles                   | 1                                                                        |
+------------------------------+--------------------------------------------------------------------------+
| nbh                          | 1                                                                        |
+------------------------------+--------------------------------------------------------------------------+
| morphology                   | <synthesizer.parametric.morphology.PointSource object at 0x7f94be1e7340> |
+------------------------------+--------------------------------------------------------------------------+
| is_parametric                | True                                                                     |
+------------------------------+--------------------------------------------------------------------------+
| is_particle                  | False                                                                    |
+------------------------------+--------------------------------------------------------------------------+
| mass                         | 100000000.00000001 Msun                                                  |
+------------------------------+--------------------------------------------------------------------------+
| accretion_rate               | 1.0000000000000002 Msun/yr                                               |
+------------------------------+--------------------------------------------------------------------------+
| bolometric_luminosity        | 5.6629751681288295e+45 erg/s                                             |
+------------------------------+--------------------------------------------------------------------------+
| hydrogen_density_blr         | 1000000000.0 cm**(-3)                                                    |
+------------------------------+--------------------------------------------------------------------------+
| velocity_dispersion_blr      | 2000 km/s                                                                |
+------------------------------+--------------------------------------------------------------------------+
| hydrogen_density_nlr         | 10000.0 cm**(-3)                                                         |
+------------------------------+--------------------------------------------------------------------------+
| velocity_dispersion_nlr      | 500 km/s                                                                 |
+------------------------------+--------------------------------------------------------------------------+
| inclination                  | 60 degree                                                                |
+------------------------------+--------------------------------------------------------------------------+
| theta_torus                  | 10 degree                                                                |
+------------------------------+--------------------------------------------------------------------------+
| torus_fraction               | 0.1111111111111111                                                       |
+------------------------------+--------------------------------------------------------------------------+
| eddington_luminosity         | 3284000000000.0005 Lsun                                                  |
+------------------------------+--------------------------------------------------------------------------+
| bb_temperature               | 223999.99999999997 K                                                     |
+------------------------------+--------------------------------------------------------------------------+
/home/runner/work/synthesizer/synthesizer/src/synthesizer/utils/ascii_table.py:65: FutureWarning: The `photo_fluxes` attribute is deprecated. Use `photo_fnu` instead. Will be removed in v1.0.0
  self.attributes[name] = getattr(obj, name)
/home/runner/work/synthesizer/synthesizer/src/synthesizer/utils/ascii_table.py:65: FutureWarning: The `photo_luminosities` attribute is deprecated. Use `photo_lnu` instead. Will be removed in v1.0.0
  self.attributes[name] = getattr(obj, name)

Particle blackholes

Creating Particle Blackholes

Before generating some simple observational quantities from physical properties we first need to create a BlackHoles object. This object can be found in synthesizer/particle/blackholes.py.

[4]:
from synthesizer.particle import BlackHoles, Gas

Lets create an instance of BlackHoles containing 4 fake black holes. To do so we can provide a number of optional keyword arguments, but for now lets just provide their masses, metallicities, coordinates and accretion rates (the parameters required for spectra calculation). Note that masses and accretion_rates are positional arguments, and must therefore always be provided for particle.BlackHoles, while parametric.BlackHoles have more flexibility.

[5]:
# Make fake properties
n = 4
masses = 10 ** np.random.uniform(low=7, high=9, size=n) * Msun
coordinates = np.random.normal(0, 1.5, (n, 3)) * Mpc
accretion_rates = 10 ** np.random.uniform(low=-2, high=1, size=n) * Msun / yr
metallicities = np.full(n, 0.01)

# And get the black holes object
bh = BlackHoles(
    masses=masses,
    coordinates=coordinates,
    accretion_rates=accretion_rates,
    metallicities=metallicities,
)

For some emission models we require an inclination. This could, in principle, be calculated from the simulation and passed at instantiation, but for now we can use an in-built method to generate random inclinations.

[6]:
bh.calculate_random_inclination()
print(bh.inclination)
[53.3173112   4.18053714 54.67903667 15.34717113] degree

Blackhole properties

On initialisation a handful of properties will automatically be calculated if their prerequisites are met. For example, if masses and accretion_rates are provided, bolometric_luminosities are automatically calculated using,

\[L_{\rm \bullet, bol} = \epsilon_{r}\dot{M}_{\bullet}c^{2}.\]

Note that the radiative efficency (epsilon) defaults to 0.1, but can be passed as an array with a value for each particle.

[7]:
bh.bolometric_luminosities
[7]:
unyt_array([7.11426744e+44, 1.32207049e+45, 1.28402223e+46, 2.24939644e+44], 'erg/s')

Here are some more examples of calculated properties.

[8]:
print(bh.eddington_ratio)
print(bh.accretion_rate_eddington)
print(bh.eddington_luminosity)
[0.00710297 0.03614141 0.64862542 0.08725034]
[2.71830651e+31 1.38313184e+32 2.48228947e+33 3.33907039e+32]
[2.61716896e+13 9.55852834e+12 5.17273365e+12 6.73659486e+11] Lsun

As with most synthesizer objects a summary of the object can be printed using print.

[9]:
print(bh)
+------------------------------------------------------------------------------------------------+
|                                           PARTICLES                                            |
+--------------------------------+---------------------------------------------------------------+
| Attribute                      | Value                                                         |
+--------------------------------+---------------------------------------------------------------+
| nparticles                     | 4                                                             |
+--------------------------------+---------------------------------------------------------------+
| metallicity_floor              | 1.00e-05                                                      |
+--------------------------------+---------------------------------------------------------------+
| name                           | 'Black Holes'                                                 |
+--------------------------------+---------------------------------------------------------------+
| component_type                 | 'BlackHoles'                                                  |
+--------------------------------+---------------------------------------------------------------+
| fesc                           | 0.00e+00                                                      |
+--------------------------------+---------------------------------------------------------------+
| ionisation_parameter_blr       | 0.10                                                          |
+--------------------------------+---------------------------------------------------------------+
| covering_fraction_blr          | 0.10                                                          |
+--------------------------------+---------------------------------------------------------------+
| ionisation_parameter_nlr       | 0.01                                                          |
+--------------------------------+---------------------------------------------------------------+
| covering_fraction_nlr          | 0.10                                                          |
+--------------------------------+---------------------------------------------------------------+
| covering_fraction              | 0.20                                                          |
+--------------------------------+---------------------------------------------------------------+
| escape_fraction                | 0.80                                                          |
+--------------------------------+---------------------------------------------------------------+
| transmission_fraction_escape   | 1.00                                                          |
+--------------------------------+---------------------------------------------------------------+
| transmission_fraction_nlr      | 0.00e+00                                                      |
+--------------------------------+---------------------------------------------------------------+
| transmission_fraction_blr      | 0.00e+00                                                      |
+--------------------------------+---------------------------------------------------------------+
| disc_transmission              | 'none'                                                        |
+--------------------------------+---------------------------------------------------------------+
| nbh                            | 4                                                             |
+--------------------------------+---------------------------------------------------------------+
| is_parametric                  | False                                                         |
+--------------------------------+---------------------------------------------------------------+
| is_particle                    | True                                                          |
+--------------------------------+---------------------------------------------------------------+
| coordinates (4, 3)             | -3.92e+00 Mpc -> 1.52e+00 Mpc (Mean: -6.07e-01 Mpc)           |
+--------------------------------+---------------------------------------------------------------+
| masses (4,)                    | 2.05e+07 Msun -> 7.97e+08 Msun (Mean: 3.17e+08 Msun)          |
+--------------------------------+---------------------------------------------------------------+
| mass (4,)                      | 2.05e+07 Msun -> 7.97e+08 Msun (Mean: 3.17e+08 Msun)          |
+--------------------------------+---------------------------------------------------------------+
| accretion_rate (4,)            | 3.97e-02 Msun/yr -> 2.27e+00 Msun/yr (Mean: 6.67e-01 Msun/yr) |
+--------------------------------+---------------------------------------------------------------+
| epsilon                        | [0.1]                                                         |
+--------------------------------+---------------------------------------------------------------+
| accretion_rate_eddington (4,)  | 2.72e+31 -> 2.48e+33 (Mean: 7.45e+32)                         |
+--------------------------------+---------------------------------------------------------------+
| bolometric_luminosity (4,)     | 2.25e+44 erg/s -> 1.28e+46 erg/s (Mean: 3.77e+45 erg/s)       |
+--------------------------------+---------------------------------------------------------------+
| metallicity (4,)               | 1.00e-02 -> 1.00e-02 (Mean: 1.00e-02)                         |
+--------------------------------+---------------------------------------------------------------+
| hydrogen_density_blr           | 1000000000.0 cm**(-3)                                         |
+--------------------------------+---------------------------------------------------------------+
| velocity_dispersion_blr        | 2000 km/s                                                     |
+--------------------------------+---------------------------------------------------------------+
| hydrogen_density_nlr           | 10000.0 cm**(-3)                                              |
+--------------------------------+---------------------------------------------------------------+
| velocity_dispersion_nlr        | 500 km/s                                                      |
+--------------------------------+---------------------------------------------------------------+
| inclination (4,)               | 4.18e+00 degree -> 5.47e+01 degree (Mean: 3.19e+01 degree)    |
+--------------------------------+---------------------------------------------------------------+
| theta_torus                    | 10 degree                                                     |
+--------------------------------+---------------------------------------------------------------+
| torus_fraction                 | 0.1111111111111111                                            |
+--------------------------------+---------------------------------------------------------------+
| eddington_luminosity (4,)      | 6.74e+11 Lsun -> 2.62e+13 Lsun (Mean: 1.04e+13 Lsun)          |
+--------------------------------+---------------------------------------------------------------+
| bb_temperature (4,)            | 4.72e+04 K -> 2.21e+05 K (Mean: 1.45e+05 K)                   |
+--------------------------------+---------------------------------------------------------------+
| eddington_ratio (4,)           | 7.10e-03 -> 6.49e-01 (Mean: 1.95e-01)                         |
+--------------------------------+---------------------------------------------------------------+
| cosine_inclination (4,)        | 5.78e-01 -> 9.97e-01 (Mean: 7.84e-01)                         |
+--------------------------------+---------------------------------------------------------------+
| accretion_rates (4,)           | 3.97e-02 Msun/yr -> 2.27e+00 Msun/yr (Mean: 6.67e-01 Msun/yr) |
+--------------------------------+---------------------------------------------------------------+
| metallicities (4,)             | 1.00e-02 -> 1.00e-02 (Mean: 1.00e-02)                         |
+--------------------------------+---------------------------------------------------------------+
| inclinations                   | 0.0 degree                                                    |
+--------------------------------+---------------------------------------------------------------+
| bolometric_luminosities (4,)   | 2.25e+44 erg/s -> 1.28e+46 erg/s (Mean: 3.77e+45 erg/s)       |
+--------------------------------+---------------------------------------------------------------+
| accretion_rates_eddington (4,) | 2.72e+31 -> 2.48e+33 (Mean: 7.45e+32)                         |
+--------------------------------+---------------------------------------------------------------+
| epsilons                       | [0.1]                                                         |
+--------------------------------+---------------------------------------------------------------+
/home/runner/work/synthesizer/synthesizer/src/synthesizer/utils/ascii_table.py:65: FutureWarning: The `particle_photo_fluxes` attribute is deprecated. Use `particle_photo_fnu` instead. Will be removed in v1.0.0
  self.attributes[name] = getattr(obj, name)
/home/runner/work/synthesizer/synthesizer/src/synthesizer/utils/ascii_table.py:65: FutureWarning: The `particle_photo_luminosities` attribute is deprecated. Use `particle_photo_lnu` instead. Will be removed in v1.0.0
  self.attributes[name] = getattr(obj, name)

Other methods

BlackHole objects have a handful of other useful methods available for calculating different derived properties.

Calculating circular velocity

We can easily calculate the circular (Keplerian) velocity

\[v_c(r) = \sqrt{\frac{G M}{r}}.\]

using the calculate_circular_velocity method.

[10]:
radial_distance = 0.1 * ly
print(bh.calculate_circular_velocity(radial_distance).to("km/s"))
[10573.18722595  6389.77488475  4700.5654096   1696.32966359] km/s

Calculating the Schwarzschild radius

We can also easily calculate the Schwarzschild radius

\[R_{\rm s} = \frac{2GM}{c^2}\]

using the calculate_schwarzschild_radius method.

[11]:
print(bh.calculate_schwarzschild_radius())
[2.35350881e+12 8.59557828e+11 4.65161953e+11 6.05793344e+10] m

Calculate the ionising photon production rate (luminosity)

There is also a method to calculate the ionising photon production rate (luminosity). This requires that we already have created the incident disc spectra and so we need to initialise a relevant grid and the DiscIncidentEmission model. There is a separate method calculate_integrated_ionising_luminosity method calculates the ionising photon luminosity integrated over all blackholes.

[12]:
from synthesizer import Grid
from synthesizer.emission_models import DiscIncidentEmission

# Open the grid.
grid = Grid("test_grid_agn-nlr")

# Get the spectra using the DiscIncidentEmission emission model.
emission_model = DiscIncidentEmission(
    grid,
    ionisation_parameter=0.01,
    hydrogen_density=1e4 * cm**-3,
    per_particle=True,
)
bh.get_spectra(emission_model)

# Calculate and print the ionising luminosity
print(bh.calculate_ionising_luminosity())

# Calculate and print the integrated ionising luminosity
print(bh.calculate_integrated_ionising_luminosity())
[8.56634667e+54 1.59191571e+55 1.54610149e+56 2.70851635e+54] 1/s
1.8180416959875812e+56 1/s

Calculate the ionisation parameter

Given a chosen radial distance and hydrogen number density, the ionisation parameter

\[U = \frac{Q_{\mathrm{H}}}{4\pi r^{2} n_{\mathrm{H}} c}\]

can also be computed directly as an immediate extension of the above formulation. For particle blackholes this is calculated for each black hole individually.

[13]:
# typical BLR parameter
radial_distance = 0.5 * ly
hydrogen_density = 1e10 * cm**-3

print(bh.calculate_ionisation_parameter(radial_distance, hydrogen_density))


# typical NLR parameters
radial_distance = 300 * ly
hydrogen_density = 1e4 * cm**-3

print(bh.calculate_ionisation_parameter(radial_distance, hydrogen_density))
[0.01016235 0.01888507 0.18341575 0.00321314] dimensionless
[0.02822876 0.05245854 0.50948821 0.0089254 ] dimensionless

These methods also work for Parametric blackholes.

[14]:
# Define emission model, omitting the per_particle argument since we have a
# Parametric blackhole
emission_model = DiscIncidentEmission(
    grid,
    ionisation_parameter=0.01,
    hydrogen_density=1e4 * cm**-3,
)
blackhole.get_spectra(emission_model)

print(blackhole.calculate_ionising_luminosity())
print(blackhole.calculate_integrated_ionising_luminosity())
print(
    blackhole.calculate_ionisation_parameter(radial_distance, hydrogen_density)
)
6.818833967166881e+55 1/s
6.818833967166881e+55 1/s
0.22470164459184333 dimensionless

Calculating black hole metallicity

If we want to calculate emission from the black hole and its surroundings we need to know the metallicity of the gas surrounding the black hole. In the example above we could have passed an array of metallicities at instantiation, but most of the time we will not know ahead of time what these values should be. Instead, we can use the gas surrounding the black hole to calculate what this metallicity is. To do this we need to first create a Galaxy with both a Gas component and BlackHoles, again using fake data.

[15]:
# Make fake gas properties
ngas = 200
ms = np.full(ngas, 10**6.5)  # Msun
pos = np.random.normal(0, 1.5, (ngas, 3))  # cMpc
hsml = np.full(ngas, 0.75)  # cMpc
metals = np.full(ngas, 0.01)

# And make the gas object
gas = Gas(
    masses=ms * Msun,
    metallicities=metals,
    coordinates=pos * Mpc,
    smoothing_lengths=hsml * Mpc,
)

# And now create the galaxy
galaxy = galaxy(stars=None, gas=gas, black_holes=bh)
/tmp/ipykernel_5173/2038858167.py:9: RuntimeWarning:
Neither dust mass nor dust to metal ratio provided. Assuming dust to metal ratio
= 0.3
  gas = Gas(
/tmp/ipykernel_5173/2038858167.py:17: RuntimeWarning:
Star forming gas particle mask not provided, setting sf_gas_mass and
sf_gas_metallicity to `None`
  galaxy = galaxy(stars=None, gas=gas, black_holes=bh)

Now we have the galaxy we can use galaxy.calculate_black_hole_metallicity() to calculate the black holes’ metallicity. This method will find all gas particles with smoothing lengths that intersect the black hole and calculate the mass–weighted average of their metallicity. If a black hole does not find any gas neighbours then a default metallicity is set instead. This defaults to solar metallicity (0.012) but can be overwritten by passing a new default_metallicity as shown below.

[16]:
galaxy.calculate_black_hole_metallicity(default_metallicity=0.07)
print("Z_BH =", galaxy.black_holes.metallicities)
Z_BH = [0.01 0.01 0.07 0.01]