def test_ec_dt_reference_sed(self): """test agnpy SED for EC on DT against the one in Figure 11 of Finke 2016""" # reference SED sampled_ec_dt_table = np.loadtxt( f"{tests_dir}/sampled_seds/ec_dt_figure_11_finke_2016.txt", delimiter=",", comments="#", ) sampled_ec_dt_nu = sampled_ec_dt_table[:, 0] * u.Hz # multiply the reference SED for 2 as this is the missing factor # in the emissivity expression in Eq. 90 of Finke 2016 sampled_ec_dt_sed = 2 * sampled_ec_dt_table[:, 1] * u.Unit("erg cm-2 s-1") # agnpy SED L_disk = 2 * 1e46 * u.Unit("erg s-1") T_dt = 1e3 * u.K csi_dt = 0.1 dt = RingDustTorus(L_disk, csi_dt, T_dt) # recompute the SED at the same ordinates where the figure was sampled ec_dt = ExternalCompton(BPL_BLOB, dt, r=1e20 * u.cm) agnpy_ec_dt_sed = ec_dt.sed_flux(sampled_ec_dt_nu) # sed comparison plot make_sed_comparison_plot( sampled_ec_dt_nu, sampled_ec_dt_sed, agnpy_ec_dt_sed, "External Compton on Ring Dust Torus", "ec_dt_comparison_figure_11_finke_2016", ) # requires that the SED points deviate less than 30% from the figure assert u.allclose( agnpy_ec_dt_sed, sampled_ec_dt_sed, atol=0 * u.Unit("erg cm-2 s-1"), rtol=0.3, )
def test_ec_dt_reference_sed(self, r): """test agnpy SED for EC on DT against the one in Figure 11 of Finke 2016""" # reference SED nu_ref, sed_ref = extract_columns_sample_file( f"{data_dir}/reference_seds/finke_2016/figure_11/ec_dt_r_{r}.txt", "Hz", "erg cm-2 s-1", ) # recompute the SED at the same ordinates where the figure was sampled ec_dt = ExternalCompton(bpwl_blob_test, dt_test, float(r) * u.cm) sed_agnpy = ec_dt.sed_flux(nu_ref) # check in a restricted energy range nu_range = [1e18, 1e28] * u.Hz make_comparison_plot( nu_ref, sed_agnpy, sed_ref, "agnpy", "Figure 11, Finke (2016)", f"External Compton on Ring Dust Torus, r = {r} cm", f"{figures_dir}/ec/dt/comparison_r_{r}_cm_figure_11_finke_2016.png", "sed", comparison_range=nu_range.to_value("Hz"), ) # requires that the SED points deviate less than 30% from the figure assert check_deviation(nu_ref, sed_agnpy, sed_ref, 0.3, nu_range)
def test_ec_blr_reference_sed(self): """test agnpy SED for EC on BLR against the one in Figure 10 of Finke 2016""" # reference SED sampled_ec_blr_table = np.loadtxt( f"{tests_dir}/sampled_seds/ec_blr_figure_10_finke_2016.txt", delimiter=",", comments="#", ) sampled_ec_blr_nu = sampled_ec_blr_table[:, 0] * u.Hz sampled_ec_blr_sed = sampled_ec_blr_table[:, 1] * u.Unit("erg cm-2 s-1") # agnpy SED L_disk = 2 * 1e46 * u.Unit("erg s-1") xi_line = 0.024 R_line = 1e17 * u.cm blr = SphericalShellBLR(L_disk, xi_line, "Lyalpha", R_line) # recompute the SED at the same ordinates where the figure was sampled ec_blr = ExternalCompton(BPL_BLOB, blr, r=1e18 * u.cm) agnpy_ec_blr_sed = ec_blr.sed_flux(sampled_ec_blr_nu) # sed comparison plot make_sed_comparison_plot( sampled_ec_blr_nu, sampled_ec_blr_sed, agnpy_ec_blr_sed, "External Compton on Spherical Shell Broad Line Region", "ec_blr_comparison_figure_10_finke_2016", ) # requires that the SED points deviate less than 30% from the figure assert u.allclose( agnpy_ec_blr_sed, sampled_ec_blr_sed, atol=0 * u.Unit("erg cm-2 s-1"), rtol=0.3, )
def test_ec_disk_reference_sed(self): """test agnpy SED for EC on Disk against the one in Figure 8 of Finke 2016""" # reference SED sampled_ec_disk_table = np.loadtxt( f"{tests_dir}/sampled_seds/ec_disk_figure_8_finke_2016.txt", delimiter=",", comments="#", ) sampled_ec_disk_nu = sampled_ec_disk_table[:, 0] * u.Hz sampled_ec_disk_sed = sampled_ec_disk_table[:, 1] * u.Unit("erg cm-2 s-1") # agnpy SED M_BH = 1.2 * 1e9 * M_sun.cgs L_disk = 2 * 1e46 * u.Unit("erg s-1") eta = 1 / 12 R_in = 6 R_out = 200 disk = SSDisk(M_BH, L_disk, eta, R_in, R_out, R_g_units=True) # recompute the SED at the same ordinates where the figure was sampled ec_disk = ExternalCompton(BPL_BLOB, disk, r=1e17 * u.cm) agnpy_ec_disk_sed = ec_disk.sed_flux(sampled_ec_disk_nu) # sed comparison plot make_sed_comparison_plot( sampled_ec_disk_nu, sampled_ec_disk_sed, agnpy_ec_disk_sed, "External Compton on Shakura Sunyaev Disk", "ec_disk_comparison_figure_8_finke_2016", ) # requires that the SED points deviate less than 40% from the figure assert u.allclose( agnpy_ec_disk_sed, sampled_ec_disk_sed, atol=0 * u.Unit("erg cm-2 s-1"), rtol=0.4, )
def test_ec_dt_vs_point_source(self): """check if in the limit of large distances the EC on the DT tends to the one of a point-like source approximating it""" r = 1e22 * u.cm # point like source approximating the dt ps_dt = PointSourceBehindJet(dt_test.xi_dt * dt_test.L_disk, dt_test.epsilon_dt) # external Compton ec_dt = ExternalCompton(bpwl_blob_test, dt_test, r) ec_ps_dt = ExternalCompton(bpwl_blob_test, ps_dt, r) # seds nu = np.logspace(15, 28) * u.Hz sed_ec_dt = ec_dt.sed_flux(nu) sed_ec_ps_dt = ec_ps_dt.sed_flux(nu) make_comparison_plot( nu, sed_ec_ps_dt, sed_ec_dt, "point source approximating the DT", "ring Dust Torus", "External Compton on Ring Dust Torus, " + r"$r = 10^{22}\,{\rm cm} \gg R_{\rm dt}$", f"{figures_dir}/ec/dt/comparison_point_source.png", "sed", ) # requires a 20% deviation from the two SED points assert check_deviation(nu, sed_ec_dt, sed_ec_ps_dt, 0.2)
def test_ec_blr_vs_point_source(self): """check if in the limit of large distances the EC on the BLR tends to the one of a point-like source approximating it""" r = 1e22 * u.cm # point like source approximating the blr ps_blr = PointSourceBehindJet(blr_test.xi_line * blr_test.L_disk, blr_test.epsilon_line) # external Compton ec_blr = ExternalCompton(bpwl_blob_test, blr_test, r) ec_ps_blr = ExternalCompton(bpwl_blob_test, ps_blr, r) # seds nu = np.logspace(15, 30) * u.Hz sed_ec_blr = ec_blr.sed_flux(nu) sed_ec_ps_blr = ec_ps_blr.sed_flux(nu) # sed comparison plot make_comparison_plot( nu, sed_ec_ps_blr, sed_ec_blr, "point source approximating the BLR", "spherical shell BLR", "External Compton on Spherical Shell BLR, " + r"$r = 10^{22}\,{\rm cm} \gg R_{\rm line}$", f"{figures_dir}/ec/blr/comparison_point_source.png", "sed", ) # requires a 20% deviation from the two SED points assert check_deviation(nu, sed_ec_ps_blr, sed_ec_blr, 0.2)
def test_ec_dt_integration_methods(self): """test EC on DT SED for different integration methods """ nu = np.logspace(15, 28) * u.Hz r = 1e20 * u.cm ec_dt_trapz = ExternalCompton(bpwl_blob_test, dt_test, r, integrator=np.trapz) ec_dt_trapz_loglog = ExternalCompton(bpwl_blob_test, dt_test, r, integrator=trapz_loglog) sed_ec_dt_trapz = ec_dt_trapz.sed_flux(nu) sed_ec_dt_trapz_loglog = ec_dt_trapz_loglog.sed_flux(nu) make_comparison_plot( nu, sed_ec_dt_trapz_loglog, sed_ec_dt_trapz, "trapezoidal log-log integration", "trapezoidal integration", "External Compton on Ring Dust Torus", f"{figures_dir}/ec/dt/comparison_integration_methods.png", "sed", ) # requires that the SED points deviate less than 20% assert check_deviation(nu, sed_ec_dt_trapz_loglog, sed_ec_dt_trapz, 0.2)
def test_ec_blr_integration_methods(self): """test EC on BLR SED for different integration methods """ nu = np.logspace(15, 28) * u.Hz r = 1e18 * u.cm ec_blr_trapz = ExternalCompton(bpwl_blob_test, blr_test, r, integrator=np.trapz) ec_blr_trapz_loglog = ExternalCompton(bpwl_blob_test, blr_test, r, integrator=trapz_loglog) sed_ec_blr_trapz = ec_blr_trapz.sed_flux(nu) sed_ec_blr_trapz_loglog = ec_blr_trapz_loglog.sed_flux(nu) # check in a restricted energy range make_comparison_plot( nu, sed_ec_blr_trapz_loglog, sed_ec_blr_trapz, "trapezoidal log-log integration", "trapezoidal integration", "External Compton on Spherical Shell Broad Line Region", f"{figures_dir}/ec/blr/comparison_integration_methods.png", "sed", ) # requires that the SED points deviate less than 30% assert check_deviation(nu, sed_ec_blr_trapz_loglog, sed_ec_blr_trapz, 0.3)
def test_ec_disk_integration_methods(self): """test EC on Disk SED for different integration methods against each other """ nu = np.logspace(15, 28) * u.Hz r = 1e18 * u.cm ec_disk_trapz = ExternalCompton(bpwl_blob_test, disk_test, r, integrator=np.trapz) ec_disk_trapz_loglog = ExternalCompton(bpwl_blob_test, disk_test, r, integrator=trapz_loglog) sed_ec_disk_trapz = ec_disk_trapz.sed_flux(nu) sed_ec_disk_trapz_loglog = ec_disk_trapz_loglog.sed_flux(nu) make_comparison_plot( nu, sed_ec_disk_trapz_loglog, sed_ec_disk_trapz, "trapezoidal log-log integration", "trapezoidal integration", "External Compton on Shakura Sunyaev Disk", f"{figures_dir}/ec/disk/comparison_integration_methods.png", "sed", ) # requires that the SED points deviate less than 20% assert check_deviation(nu, sed_ec_disk_trapz_loglog, sed_ec_disk_trapz, 0.2)
def test_ec_dt_vs_point_source(self): """check if in the limit of large distances the EC on the DT tends to the one of a point-like source approximating it""" # dust torus L_disk = 2 * 1e46 * u.Unit("erg s-1") T_dt = 1e3 * u.K csi_dt = 0.1 dt = RingDustTorus(L_disk, csi_dt, T_dt) # point like source approximating the dt ps_dt = PointSourceBehindJet(dt.xi_dt * L_disk, dt.epsilon_dt) # external Compton ec_dt = ExternalCompton(BPL_BLOB, dt, r=1e22 * u.cm) ec_ps_dt = ExternalCompton(BPL_BLOB, ps_dt, r=1e22 * u.cm) # seds nu = np.logspace(15, 28) * u.Hz ec_dt_sed = ec_dt.sed_flux(nu) ec_ps_dt_sed = ec_ps_dt.sed_flux(nu) # requires a 20% deviation from the two SED points assert u.allclose( ec_dt_sed, ec_ps_dt_sed, atol=0 * u.Unit("erg cm-2 s-1"), rtol=0.2 )
def test_ec_blr_vs_point_source(self): """check if in the limit of large distances the EC on the BLR tends to the one of a point-like source approximating it""" # broad line region L_disk = 2 * 1e46 * u.Unit("erg s-1") xi_line = 0.024 R_line = 1e17 * u.cm blr = SphericalShellBLR(L_disk, xi_line, "Lyalpha", R_line) # point like source approximating the blr ps_blr = PointSourceBehindJet(blr.xi_line * L_disk, blr.epsilon_line) # external Compton ec_blr = ExternalCompton(BPL_BLOB, blr, r=1e22 * u.cm) ec_ps_blr = ExternalCompton(BPL_BLOB, ps_blr, r=1e22 * u.cm) # seds nu = np.logspace(15, 28) * u.Hz ec_blr_sed = ec_blr.sed_flux(nu) ec_ps_blr_sed = ec_ps_blr.sed_flux(nu) # requires a 20% deviation from the two SED points assert u.allclose( ec_blr_sed, ec_ps_blr_sed, atol=0 * u.Unit("erg cm-2 s-1"), rtol=0.2 )
csi_line = 0.024 R_line = 1e17 * u.cm blr = SphericalShellBLR(disk, csi_line, epsilon_line, R_line) print("\nblr definition:") print(blr) # dust torus definition T_dt = 1e3 * u.K epsilon_dt = 2.7 * ((const.k_B * T_dt) / (const.m_e * const.c * const.c)).decompose() csi_dt = 0.1 dt = RingDustTorus(disk, csi_dt, epsilon_dt) print("\ntorus definition:") print(dt) # define the External Compton ec_disk = ExternalCompton(blob, disk, r=1e17 * u.cm) ec_blr = ExternalCompton(blob, blr, r=1e17 * u.cm) ec_dt = ExternalCompton(blob, dt, r=1e17 * u.cm) nu = np.logspace(15, 30) * u.Hz # commands to profile ec_disk_sed_command = "ec_disk.sed_flux(nu)" ec_blr_sed_command = "ec_blr.sed_flux(nu)" ec_dt_sed_command = "ec_dt.sed_flux(nu)" n = 100 print("\nprofiling sed computation external compton on disk:") profile(ec_disk_sed_command, "ec_disk_sed") time_ec_disk = timing(ec_disk_sed_command, n) time_ec_disk /= n
print( "energy density in the blob, DT radiation: ", u_dt1, "synchrotron photons: ", u_synch1, ) dt1_sed = dt1.sed_flux(nu, z) # energy density was set to be the same synch1 = Synchrotron(blob1, ssa=False) synch1_sed = synch1.sed_flux(nu) ssc1 = SynchrotronSelfCompton(blob1, synch1) ssc1_sed = ssc1.sed_flux(nu) ec_dt1 = ExternalCompton(blob1, dt1, h) ec_dt1_sed = ec_dt1.sed_flux(nu) ssc1_total = (np.trapz(ssc1_sed / nu, nu)).to("erg cm-2 s-1") ec_dt1_total = (np.trapz(ec_dt1_sed / nu, nu)).to("erg cm-2 s-1") print("SSC total=", ssc1_total, ", EC DT total=", ec_dt1_total) # similar density of radiation but there is a factor of ~1.4 difference in the integrated flux # this probably comes from different angular distribution of the radiation gbreakssc = blob1.gamma_break_SSC gbreakdt = blob1.gamma_break_EC_DT(dt1, h) print( "break SSC=", gbreakssc, ", break EC=", gbreakdt, ", ratio: ", gbreakssc / gbreakdt ) # values of the break scale with energy density so they are the same
import numpy as np import astropy.units as u import astropy.constants as const from agnpy.emission_regions import Blob from agnpy.compton import ExternalCompton from agnpy.targets import SSDisk from agnpy.utils.plot import plot_sed import matplotlib.pyplot as plt # define the emission region blob = Blob() # define the target M_BH = 1.2 * 1e9 * const.M_sun L_disk = 2 * 1e46 * u.Unit("erg s-1") eta = 1 / 12 R_in = 6 R_out = 200 disk = SSDisk(M_BH, L_disk, eta, R_in, R_out, R_g_units=True) # declare the external Compton process r = 1e17 * u.cm # distance between the blob and the target ec = ExternalCompton(blob, disk, r) # compute the SED over an array of frequencies nu = np.logspace(15, 30) * u.Hz sed = ec.sed_flux(nu) # plot it plot_sed(nu, sed, label="External Compton on Dust Torus") plt.ylim([1e-14, 1e-8]) plt.show()
L_disk = 2 * 1e46 * u.Unit("erg s-1") # dust torus T_dt = 1e3 * u.K csi_dt = 0.1 dt = RingDustTorus(L_disk, csi_dt, T_dt) # blr xi_line = 0.024 R_line = 1e17 * u.cm blr = SphericalShellBLR(L_disk, xi_line, "Lyalpha", R_line) # point source behind the jet approximating the DT ps_dt = PointSourceBehindJet(dt.xi_dt * L_disk, dt.epsilon_dt) # point source behind the jet approximating the BLR ps_blr = PointSourceBehindJet(blr.xi_line * L_disk, blr.epsilon_line) ec_dt = ExternalCompton(blob, dt, r=1e22 * u.cm) ec_blr = ExternalCompton(blob, blr, r=1e22 * u.cm) ec_ps_dt = ExternalCompton(blob, ps_dt, r=1e22 * u.cm) ec_ps_blr = ExternalCompton(blob, ps_blr, r=1e22 * u.cm) # seds nu = np.logspace(15, 30) * u.Hz sed_blr = ec_blr.sed_flux(nu) sed_ps_blr = ec_ps_blr.sed_flux(nu) sed_dt = ec_dt.sed_flux(nu) sed_ps_dt = ec_ps_dt.sed_flux(nu) plt.loglog(nu, sed_blr, ls="-", lw=2, color="k", label="EC on BLR") plt.loglog(nu, sed_dt, ls="-", lw=2, color="dimgray", label="EC on DT") plt.loglog(