In [2]:
import numpy as np
import matplotlib.pyplot as plt

font = {'size'   : 15}
matplotlib.rc('font', **font)

In [3]:
import cosmology as cosm
from scipy.interpolate import interp1d

Number of X-ray echoes from the IGM given $\delta t_{max}$ and $\nu_{fb}$

The relation

$$ N_{ech} \sim \delta t_{\rm max}\ \nu_{fb}\ N_q(F \geq F_{th}) $$

is highly dependant on the threshold flux $F_{th}$ necessary to produce observable scattering echoes. Main factors contributing to the threshold flux are:

  • instrument background
  • exposure time
  • abundance of IGM dust

Furthermore, the $\delta t_{\rm max}$ and Nq are linked because the brighter quasars will produce the most visibly extended halos and are thereby capable of a larger $\delta t{\rm max}$ (Figure~3).

I address this in Section 3.2, fourth paragraph when I point out that:

$$ \delta t_{\rm max} N_q (F \geq F_{th}) \sim 1000\ {\rm years} $$

Since these values are highly dependent on the instrument, a more appropriate value to preserve for posterity may be the fraction of quasars (assuming a perfect instrument with zero background), around which X-ray scattering echoes may be expected.

$$ f \equiv \frac{ N_{ech} }{ N_q } = \delta t_{\rm max} \nu_{fb}$$

Put another way,

$$ \log \nu_{fb} = \log f - \log \delta t_{\rm max} $$

which means I will be plotting straight lines.

In [4]:
log_tmax = np.linspace(0.0, 5.0, 50)
log_f    = [-2.0, -1.0, np.log10(0.5), 0.0]

lf_color = dict(zip(log_f, ['0.9','0.7','0.5','k']))

log_nufb = { LF:(LF - log_tmax) for LF in log_f }

for LF in log_f:
    plt.plot( log_tmax, log_nufb[LF], color=lf_color[LF], lw=2 )

plt.xlabel(r'$\log\ \delta t_{\rm max}$ [yrs]')
plt.ylabel(r'$\log\ \nu_{\rm fb}$ [yrs$^{-1}$]')

plt.text(0.8, -3.5, '1%', color='0.7')
plt.text(3.8, -3.5, '100%', color='k')

plt.axvline(3.0, color='k', ls=':')
plt.axhline(-4.0, color='k', ls=':')
#plt.axvline(4.0, color='k', ls=':')
#plt.axhline(-5.0, color='k', ls=':')

plt.ylim(-7, 0)

(-7, 0)

How should one read this plot?

The 100% marks the $\delta t_{\rm max} < \nu_{fb}^{-1}$ limit. But anyways ...

Take for example 1 um grains, which produce more compact scattering halos that only last up to $10^3$ years (Figure~3). If $\nu_{fb} \leq 10^{-4}$~yrs$^{-1}$, then less than 10\% of quasars will have a ghost echo.

Ready differently (and taking 0.1 um grains), if $\nu_{fb} \sim 10^{-4}$~yrs$^{-1}$, then 90% of AGN will have a ghost halo after $10^3$~years, and 0% after $10^4$~years.

This could have implications for the unresolved soft X-ray background, if there is a sufficient enough column density (e.g. Dijkstra & Loeb paper).

Cases with $\nu_{fb}^{-1} < \delta t_{\rm max}$

In this case, one should replace $\delta t_{\rm max}$ with $\nu_{fb}^{-1}$ so that:

$$ \nu_{\rm fb}^{-1} \approx \frac{\alpha^2 D_R}{c} \left( 1 - \frac{\alpha}{2 \sigma} \right) $$

In [5]:
## from figure03.ipynb

C      = 3.e10 # cm/s
GPC    = 1.e9 * 3.e18 # cm
ARCSEC = 5.e-6 # radians
ARCMIN = 3.e-4 # radians
YEAR   = 3.e7 # seconds

ZS = 2.0

def charsig(a, E):
    """ returns the characteristic scattering angle, in arcseconds
     a: [um] Grain size
     E: [keV] Photon energy"""
    charsig0 = 1.04 * 60 # arcsec per 1 um grain size per keV
    return charsig0 / a / E

def tmax(alpha, a=0.1, E=1.0, zs=ZS):
    """ Calculate the maximum time delay associated with 
        observation angle and typical grain population
        alpha: [arcmin] Observation angle
        a: [micron] Grain size
        E: [keV] Photon energy
        zs: Redshift of source"""
    time_os   = cosm.DChi(zs, 0.0) * (GPC/C) / YEAR
    alpha_rad = alpha * ARCSEC
    xterm     = 1 - alpha/(2*charsig(a,E))
    return time_os * alpha_rad**2 * xterm

In [6]:
def alpha_ring( nu_fb, alpha, a=0.1, E=1.0, zs=ZS ):
    delta_t = tmax( alpha, a=a, E=E, zs=zs)
    result  = interp1d( delta_t, alpha )
    return result( np.power(nu_fb,-1.0) )

In [7]:
#ALPHA = np.linspace(1.0,1000.0,500) # arcsec, 2'' spacing
ALPHA  = np.logspace(-1.0,3.0,100)

ZS_GRID = [2, 4, 6]

nu_fb = np.logspace(-4,0,50)

rings_2 = alpha_ring(nu_fb, np.logspace(-1.0,3.0,100), zs=2.0)
rings_6 = alpha_ring(nu_fb, np.logspace(-1.0,3.0,100), zs=6.0)

In [8]:
plt.plot( ALPHA, tmax(ALPHA, zs=2.0), 'k-', lw=2 )
plt.plot( ALPHA, tmax(ALPHA, zs=6.0), 'k--', lw=2 )
plt.xlabel(r'$\alpha$ [arcsec]')
plt.ylabel(r'$\delta t_{\rm max}$[yrs]')

<matplotlib.text.Text at 0x10b4b7990>

In [9]:
plt.plot( np.log10(nu_fb), rings_2, 'k-', lw=2, label='$z_s = 2$')
plt.plot( np.log10(nu_fb), rings_6, 'k--', lw=2, label='$z_s = 6$')

plt.legend(loc='upper right', fontsize=12)

plt.ylabel('Ring radius [arcsec]')
plt.xlabel(r'$\log \nu_{\rm fb}$ [yrs$^{-1}$]')

(1.0, 200.0)

But this plot can easily be read from Figure~3, where you replace $\delta t_{\rm max}$ with $\nu_{fb}^{-1}$

Redo the first plot, but replaces $\delta t_{\rm max}$ with $\alpha$

In [16]:
new_log_tmax = np.log10( tmax(ALPHA) )
new_log_nufb = { LF:(LF - new_log_tmax) for LF in log_f }

for LF in log_f:
    plt.plot( ALPHA, new_log_nufb[LF], color=lf_color[LF], lw=2 )


plt.xlabel(r'Halo radius [arcsec]')
plt.ylabel(r'$\log\ \nu_{\rm fb}$ [yrs$^{-1}$]')

plt.text(2.0, -3.0, '1%', color='0.7')
plt.text(100, -3.0, '100%', color='k')

plt.axhline(-4.0, color='k', ls=':')
plt.axvline(50.0, color='k', ls=':')
plt.axvline(100.0, color='k', ls=':')

#plt.savefig('figure04.pdf', format='pdf')

<matplotlib.lines.Line2D at 0x10bd34510>

In [10]: