def plot_S_model(): # Debug plotting B = 5e-10 print('huhu') nu_range = np.logspace(np.log10(30e6), 9, 6) age_range = np.linspace(0, 200, 5) from agnpy.emission_regions import Blob from agnpy.synchrotron import Synchrotron blob = Blob(z=0.001, B=10**4 * B * u.gauss, spectrum_dict={ "type": "PowerLaw", "parameters": { "p": 2.3, "gamma_min": 2, "gamma_max": 1e7 } }) synch = Synchrotron(blob) sed = synch.sed_flux(nu_range * u.Hz) sed = sed.value / nu_range results = np.zeros((len(age_range), len(nu_range))) for i, age in enumerate(age_range): with mp.Pool() as p: results[i] = p.starmap(S_model, [[nu, B, 0.65, 1000, age] for nu in nu_range]) print(results[i], nu_range) PL = (nu_range**-0.65) PL /= (PL[0] / sed[0]) print((results[0, 0] / sed[0])) results /= (results[0, 0] / sed[0]) import matplotlib.pyplot as plt plt.close() print(nu_range, sed) plt.plot(nu_range, sed, c='k', label=f'AGNPY for 0 Myr; B = {B}T') plt.plot(nu_range, PL, label=f'PL alpha = 0.65', c='k', ls='dotted') for age, res in zip(age_range, results): plt.plot(nu_range, res, label=f'{age}Myr; B = {B}T') plt.xscale('log') plt.yscale('log') plt.xlabel('frequency [Hz]') plt.ylabel('S') # plt.xlim([np.min(nu_range), np.max(nu_range)]) # plt.ylim([np.min(res), 1.05*np.max(res)]) plt.legend() plt.savefig( __file__.replace('lib_aging.py', '') + 'lib_aging_data/synch_vs_nu.png')
def test_ssa_reference_sed( self, file_ref, spectrum_type, spectrum_parameters, figure_title, figure_path, ): """test SSA SED generated by a given electron distribution against the ones generated with jetset version 1.1.2, via jetset_ssa_sed.py script""" # reference SED nu_ref, sed_ref = extract_columns_sample_file(file_ref, "Hz", "erg cm-2 s-1") # same parameters used to produce the jetset SED spectrum_norm = 1e2 * u.Unit("cm-3") spectrum_dict = { "type": spectrum_type, "parameters": spectrum_parameters } blob = Blob( R_b=5e15 * u.cm, z=0.1, delta_D=10, Gamma=10, B=0.1 * u.G, spectrum_norm=spectrum_norm, spectrum_dict=spectrum_dict, ) # recompute the SED at the same ordinates where the figure was sampled ssa = Synchrotron(blob, ssa=True) sed_agnpy = ssa.sed_flux(nu_ref) # sed comparison plot, we will check between 10^(11) and 10^(19) Hz nu_range = [1e11, 1e19] * u.Hz make_comparison_plot( nu_ref, sed_agnpy, sed_ref, "agnpy", "jetset 1.1.2", figure_title, figure_path, "sed", comparison_range=nu_range.to_value("Hz"), ) # requires that the SED points deviate less than 5% from the figure assert check_deviation(nu_ref, sed_agnpy, sed_ref, 0.05, nu_range)
def test_absorption_pointlike_and_homogeneous(self): """Simple test for checking the attenuation factors in both considered cases.""" blob = Blob() absorb = Absorption(blob) nu_tau = np.logspace(22, 34, 100) * u.Hz # for absorption calculations tau = absorb.tau(nu_tau) abs_pointlike = absorb.absorption(nu_tau) abs_homogeneous = absorb.absorption_homogeneous(nu_tau) # select good points (to avoid division by zero) idxs = tau > 1.0e-3 # if this fails something is wrong with the test itself (e.g. default parameters of the blob) assert sum(idxs) > 10 # the formulas reproduce what should be in the function, so the agreement should be down to numerical accuracy assert np.allclose(np.exp(-tau), abs_pointlike, atol=1.0e-5) assert np.allclose((1 - np.exp(-tau)) / tau, abs_homogeneous, atol=1.0e-5)
}, } R_b = 1e16 * u.cm B = 1 * u.G z = Distance(1e27, unit=u.cm).z delta_D = 10 Gamma = 10 for spectrum_dict in (spectrum_dict_pwl, spectrum_dict_bpl, spectrum_dict_bpl_2): for norm_type in ("integral", "differential", "gamma=1"): blob = Blob( R_b, z, delta_D, Gamma, B, spectrum_norm, spectrum_dict, spectrum_norm_type=norm_type, ) blob.plot_n_e() # let us trigger the error blob = Blob( R_b, z, delta_D, Gamma, B, 1e48 * u.Unit("erg"), spectrum_dict_bpl_2,
r0 = 1.0e14 * u.m dist = 3.0e16 * u.cm xi = 1.0e-4 nu = np.logspace(8, 26, 200) * u.Hz norm = 15000.0 * u.Unit("cm-3") parameters = { "p1": 2.0, "p2": 3.0, "gamma_b": gbreak, "gamma_min": gmin0, "gamma_max": gmax0, } spectrum_dict = {"type": "BrokenPowerLaw", "parameters": parameters} blob = Blob(r0, z, delta_D, Gamma, B0, norm, spectrum_dict, xi=xi) # plt.loglog(blob.gamma, blob.n_e (blob.gamma)) ############################################# # limits from confinement of particles inside the blob: gmaxconf = blob.gamma_max_larmor # computing larmor radius of this electron, should be of the size of the blob # R_L = 33.36 km * (p/(GeV/c)) * (G/B) * Z^-1 # https://w3.iihe.ac.be/~aguilar/PHYS-467/PA3.pdf rlarmor = (33.36 * u.km * gmaxconf * 511.0e3 / 1.0e9 / (blob.B / u.G)).to("cm") # both values are similar print("R_L (gmaxconf)=", rlarmor, "R_b=", blob.R_b) #############################################
"p1": 1.5, "p2": 2.5, "gamma_b": 1.0e3, "gamma_min": 1, "gamma_max": 1.0e6, } spectrum_dict = {"type": "BrokenPowerLaw", "parameters": parameters} delta_D = 1.01 Gamma = 1.01 B = 1.0 * u.G r_b = 1.0e15 * u.cm # no beaming blob0 = Blob(r_b, 0.01, delta_D, Gamma, B, spectrum_norm, spectrum_dict, xi=0.01) synch0 = Synchrotron(blob0, ssa=True) synch0_sed = synch0.sed_flux(nu) # beaming delta_D = 20 Gamma = 15 blob1 = Blob(r_b, 0.01, delta_D, Gamma, B,
from astropy.coordinates import Distance from agnpy.emission_regions import Blob import matplotlib.pyplot as plt from agnpy.utils.plot import load_mpl_rc # matplotlib adjustments load_mpl_rc() # set the spectrum normalisation (total energy in electrons in this case) spectrum_norm = 1e48 * u.Unit("erg") # define the spectral function parametrisation through a dictionary spectrum_dict = { "type": "PowerLaw", "parameters": { "p": 2.8, "gamma_min": 1e2, "gamma_max": 1e7 }, } # set the remaining quantities defining the blob R_b = 1e16 * u.cm B = 1 * u.G z = Distance(1e27, unit=u.cm).z delta_D = 10 Gamma = 10 blob = Blob(R_b, z, delta_D, Gamma, B, spectrum_norm, spectrum_dict) # plot the electron distribution blob.plot_n_e(gamma_power=2) plt.show()
bpwl_dict_test = { "type": "BrokenPowerLaw", "parameters": { "p1": 2.0, "p2": 3.5, "gamma_b": 1e4, "gamma_min": 20, "gamma_max": 5e7, }, } # blob reproducing Figure 7.4 of Dermer Menon 2009 pwl_blob_test = Blob( 1e16 * u.cm, Distance(1e27, unit=u.cm).z, 10, 10, 1 * u.G, pwl_spectrum_norm_test, pwl_dict_test, ) # blob reproducing the EC scenarios in Finke 2016 bpwl_blob_test = Blob( 1e16 * u.cm, 1, 40, 40, 0.56 * u.G, bpwl_spectrum_norm_test, bpwl_dict_test, ) bpwl_blob_test.set_gamma_size(400)
def test_tau_on_synchrotron_compare_with_delta_approximation(self): """Compare the output of the calculation of absorption of gamma rays in synchrotron radiation and compare it with simplified delta approximation. """ # create a test blob r_b = 1.0e16 * u.cm z = 2.01 delta_D = 10.1 Gamma = 10.05 B0 = 1.1 * u.G gmin = 10 gbreak = 1.0e3 gmax = 1.0e5 spectrum_norm = 0.1 * u.Unit("erg cm-3") parameters = { "p1": 1.5, "p2": 2.5, "gamma_b": gbreak, "gamma_min": gmin, "gamma_max": gmax, } spectrum_dict = {"type": "BrokenPowerLaw", "parameters": parameters} blob = Blob(r_b, z, delta_D, Gamma, B0, spectrum_norm, spectrum_dict) nu_tau = np.logspace(22, 34, 100) * u.Hz # for absorption calculations e_tau = nu_tau.to("eV", equivalencies=u.spectral()) # full calculations absorb = Absorption(blob) tau = absorb.tau(nu_tau) # now simplified calculations using Eq. 37 of Finke 2008 mec2 = (m_e * c**2).to("eV") eps1 = e_tau / mec2 eps1p = eps1 * (1 + z) / blob.delta_D eps_bar = 2 * blob.delta_D**2 / (1 + z)**2 / eps1 nu_bar = (eps_bar * mec2).to("Hz", equivalencies=u.spectral()) synch = Synchrotron(blob, ssa=True) synch_sed_ebar = synch.sed_flux(nu_bar) tau_delta = (synch_sed_ebar * sigma_T * Distance(z=z)**2 * eps1p / (2 * m_e * c**3 * blob.R_b * blob.delta_D**4)) tau_delta = tau_delta.to("") # the delta approximation does not work well with sharp cut-offs of synchrotron SED. # We first find the peak of the synchr SED maxidx = np.where(synch_sed_ebar == np.amax(synch_sed_ebar))[0][0] # and only take energies below the peak, (note that energies are ordered # in reversed order), and take only those that are at least 1% of the peak idxs = synch_sed_ebar[maxidx:] > 1.0e-2 * synch_sed_ebar[maxidx] # if there are not many points something went wrong with the test assert sum(idxs) > 10 # the agreement in the middle range is pretty good, but at the edges # of energy range it spoils very fast, so only rough agreement is checked # (0.6 in the log space) assert np.allclose(np.log(tau)[maxidx:][idxs], np.log(tau_delta)[maxidx:][idxs], atol=0.6)
import numpy as np import astropy.units as u from agnpy.emission_regions import Blob from agnpy.compton import SynchrotronSelfCompton from agnpy.utils.plot import plot_sed import matplotlib.pyplot as plt from agnpy.utils.plot import load_mpl_rc # matplotlib adjustments load_mpl_rc() # define the emission region and the radiative process blob = Blob() ssc = SynchrotronSelfCompton(blob) # compute the SED over an array of frequencies nu = np.logspace(15, 28) * u.Hz sed = ssc.sed_flux(nu) # plot it plot_sed(nu, sed, label="Synchrotron Self Compton") plt.show()
import numpy as np import astropy.units as u from astropy.coordinates import Distance from astropy.constants import e, c, m_e, M_sun, G, sigma_sb from agnpy.emission_regions import Blob from agnpy.targets import ( CMB, PointSourceBehindJet, SSDisk, SphericalShellBLR, RingDustTorus, ) import pytest # variables with _test are global and meant to be used in all tests blob_test = Blob() # CMB at z = 1 cmb_test = CMB(z=1) # PointSourceBehindJet ps_test = PointSourceBehindJet(1e46 * u.Unit("erg s-1"), 1e-5) # disk M_BH_test = 1.2 * 1e9 * M_sun L_disk_test = 1.512 * 1e46 * u.Unit("erg s-1") eta_test = 1 / 12 R_g_test = 1.77 * 1e14 * u.cm R_in_tilde_test = 6 R_out_tilde_test = 200 R_in_test = R_in_tilde_test * R_g_test
spectrum_norm = 6e42 * u.erg parameters = { "p1": 2.0, "p2": 3.5, "gamma_b": 1e4, "gamma_min": 20, "gamma_max": 5e7, } spectrum_dict = {"type": "BrokenPowerLaw", "parameters": parameters} R_b = 1e16 * u.cm B = 0.56 * u.G z = 1 delta_D = 40 Gamma = 40 blob = Blob(R_b, z, delta_D, Gamma, B, spectrum_norm, spectrum_dict) blob.set_gamma_size(500) 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
# global PWL blob, same parameters of Figure 7.4 in Dermer Menon 2009 SPECTRUM_NORM = 1e48 * u.Unit("erg") PWL_DICT = { "type": "PowerLaw", "parameters": { "p": 2.8, "gamma_min": 1e2, "gamma_max": 1e5 }, } R_B = 1e16 * u.cm B = 1 * u.G Z = Distance(1e27, unit=u.cm).z DELTA_D = 10 GAMMA = 10 PWL_BLOB = Blob(R_B, Z, DELTA_D, GAMMA, B, SPECTRUM_NORM, PWL_DICT) # global blob with BPL law of electrons, to test the parametrisation of the # delta function approximation BPL_DICT = { "type": "BrokenPowerLaw", "parameters": { "p1": 2.5, "p2": 3.5, "gamma_b": 1e4, "gamma_min": 1e2, "gamma_max": 1e7, }, } BPL_BLOB = Blob(R_B, Z, DELTA_D, GAMMA, B, SPECTRUM_NORM, BPL_DICT)
"gamma_0": 1e3, "gamma_min": gamma_min_test, "gamma_max": gamma_max_test, }, } # blob parameters R_b_test = 1e16 * u.cm z_test = 0.1 delta_D_test = 10 Gamma_test = 10 B_test = 0.1 * u.G pwl_blob_test = Blob( R_b_test, z_test, delta_D_test, Gamma_test, B_test, spectrum_norm_test, pwl_dict_test, ) bpwl_blob_test = Blob( R_b_test, z_test, delta_D_test, Gamma_test, B_test, spectrum_norm_test, bpwl_dict_test, ) lp_blob_test = Blob( R_b_test,
##################### # test one with emission region in the center of the DT L_disk = 0.91e45 * u.Unit("erg s-1") xi_dt = 0.6 T_dt = 100 * u.K R_dt = 1.0e18 * u.cm h = 0.01 * R_dt ## test with lower numbers, gives virtually the same # B0/=10 # T_dt/=10 # L_disk/=100 blob1 = Blob(r0, z, delta_D, Gamma, B0, norm, spectrum_dict, xi=xi) dt1 = RingDustTorus(L_disk, xi_dt, T_dt, R_dt=R_dt) # energy density of DT radiation field in the blob u_dt1 = dt1.u_ph(h, blob1) u_synch1 = blob1.u_ph_synch 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)
mec2 = m_e.to("erg", equivalencies=u.mass_energy()) # a global test blob with spectral index 2 SPECTRUM_NORM = 1e-13 * u.Unit("cm-3") GAMMA_MIN = 1 GAMMA_MAX = 1e6 PWL_IDX_2_DICT = { "type": "PowerLaw", "parameters": {"p": 2.0, "gamma_min": GAMMA_MIN, "gamma_max": GAMMA_MAX}, } # blob parameters R_B = 1e16 * u.cm Z = 0.1 DELTA_D = 10 GAMMA = 10 B = 0.1 * u.G PWL_BLOB = Blob(R_B, Z, DELTA_D, GAMMA, B, SPECTRUM_NORM, PWL_IDX_2_DICT) # useful for checks BETA = 1 - 1 / np.power(GAMMA, 2) V_B = 4 / 3 * np.pi * np.power(R_B, 3) class TestBlob: """class grouping all tests related to the Blob emission region""" def test_default_norm_type(self): """the default norm type should be 'integral'""" assert PWL_BLOB.spectrum_norm_type == "integral" def test_integral_norm_cm3(self): """test if the integral norm in cm-3 is correctly set""" PWL_BLOB.set_n_e(SPECTRUM_NORM, PWL_IDX_2_DICT, "integral")
n = -2.0 x = np.logspace(2, 5) y = line_loglog(x, m, n) analytical_integral = integral_line_loglog(x[0], x[-1], m, n) trapz_loglog_integral = trapz_loglog(y, x) np_trapz_integral = np.trapz(y, x) print(f"analyitcal integral: {analytical_integral:e}") print(f"trapz_loglog integral: {analytical_integral:e}") print(f"np.trapz integral: {analytical_integral:e}") # a test with sycnhrotron radiation print("-> test with synchrotron radiation") blob = Blob() nu = np.logspace(9, 20, 20) * u.Hz # check the blob print(blob) def sed_synch(nu, blob, integration): """compute the synchrotron SED""" epsilon = nu_to_epsilon_prime(nu, blob.z, blob.delta_D) # electrond distribution lorentz factor gamma = blob.gamma N_e = blob.N_e(gamma) prefactor = np.sqrt(3) * epsilon * np.power(e, 3) * blob.B_cgs / h # for multidimensional integration # axis 0: electrons gamma
# define the blob spectrum_norm = 6e42 * u.erg parameters = { "p1": 2.0001, "p2": 3.5, "gamma_b": 1e4, "gamma_min": 20, "gamma_max": 5e7, } spectrum_dict = {"type": "BrokenPowerLaw", "parameters": parameters} R_b = 1e16 * u.cm B = 0.56 * u.G z = 1 delta_D = 40 Gamma = 40 blob = Blob(R_b, z, delta_D, Gamma, B, spectrum_norm, spectrum_dict) print("\nblob definition:") print(blob) # disk parameters M_sun = const.M_sun.cgs M_BH = 1.2 * 1e9 * M_sun R_g = ((const.G * M_BH) / (const.c * const.c)).cgs L_disk = 2 * 1e46 * u.Unit("erg s-1") eta = 1 / 12 R_in = 6 * R_g R_out = 200 * R_g disk = SSDisk(M_BH, L_disk, eta, R_in, R_out) print("\ndisk definition:") print(disk)
fig.savefig(f"{tests_dir}/crosscheck_figures/{fig_name}.png") # global PWL blob, same parameters of Figure 7.4 in Dermer Menon 2009 PWL_SPECTRUM_NORM = 1e48 * u.Unit("erg") PWL_DICT = { "type": "PowerLaw", "parameters": {"p": 2.8, "gamma_min": 1e2, "gamma_max": 1e5}, } R_B_PWL = 1e16 * u.cm B_PWL = 1 * u.G Z_PWL = Distance(1e27, unit=u.cm).z DELTA_D_PWL = 10 GAMMA_PWL = 10 PWL_BLOB = Blob( R_B_PWL, Z_PWL, DELTA_D_PWL, GAMMA_PWL, B_PWL, PWL_SPECTRUM_NORM, PWL_DICT ) # global BPL blob, same parameters of the examples in Finke 2016 BPL_SPECTRUM_NORM = 6e42 * u.Unit("erg") BPL_DICT = { "type": "BrokenPowerLaw", "parameters": { "p1": 2.0, "p2": 3.5, "gamma_b": 1e4, "gamma_min": 20, "gamma_max": 5e7, }, } R_B_BPL = 1e16 * u.cm