Skip to content

Commit 758d79c

Browse files
committed
Improved documentation
1 parent 7612417 commit 758d79c

10 files changed

Lines changed: 202 additions & 103 deletions

File tree

Examples.ipynb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@
5959
"Number of points in the n=1 grid 6250000\n",
6060
"Number of points in the n=2 grid 6250000\n",
6161
"File ./Results/LensingBands_a_0.94_i_17.h5 created.\n",
62-
"CPU times: user 814 ms, sys: 274 ms, total: 1.09 s\n",
63-
"Wall time: 52 s\n"
62+
"CPU times: user 929 ms, sys: 324 ms, total: 1.25 s\n",
63+
"Wall time: 56.1 s\n"
6464
]
6565
}
6666
],

README.md

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@ The code, described in detail in Ref. [1], implements all the relevant equations
66

77
The use of AART in scientific publications must be properly acknowledged. Please cite:
88

9-
Cardenas-Avendano, A., Zhu, H. & Lupsasca, A.
10-
Adaptive Analytical Ray-Tracing of Black Hole Photon Rings.
11-
[arXiv:Please come back soon for the reference!]
9+
_______
10+
Cardenas-Avendano, A., Lupsasca, A. & Zhu, H. "Adaptive Analytical Ray Tracing of Black Hole Photon Rings." [arXiv:2211.07469](https://arxiv.org/abs/2211.07469)
11+
_______
1212

1313
We also request that AART modifications or extensions leading to a scientific publication be made public as free software.
1414

1515
<center> <em>Feel free to use images and movies produced with this code (with attribution) for your next presentation! </em> </center>
1616

17-
Last updated: 07.03.2022
17+
Last updated: 11.15.2022
1818

1919
## AART's Components ##
2020

@@ -37,11 +37,15 @@ All the dependencies are located in the <em>init.py</em> file. Most of the libra
3737

3838
To install any missing packages, run
3939

40-
<code> >> pip install "package_name" </code>
40+
<code> pip install "package_name" </code>
4141

42-
or, if using anaconda, search for the missing packages and run, e.g. for h5py (Read and write HDF5 files from Python,)
42+
or, if using anaconda, search for the missing packages and run, e.g. for h5py (Read and write HDF5 files from Python,)
4343

44-
<code> conda install -c anaconda h5py</code>
44+
<code> conda install -c anaconda h5py</code>
45+
46+
Sometimes scipy does not update automatically to the latest version. If that is the case, you may want to type
47+
48+
<code> pip install -U scipy</code>
4549

4650

4751
## How to run AART ##
@@ -56,7 +60,7 @@ We present some examples in the notebook:
5660

5761
The lensing bands are computed by simply running
5862

59-
<code> >> python lensingbands.py </code>
63+
<code> python lensingbands.py </code>
6064

6165
The result will be stored in a HDF5 file that contains the values of the Bardeen's coordinates withing each lensing band. The datasets inside the resulting file are:
6266

@@ -77,7 +81,7 @@ This image is produced in the example code:
7781

7882
To compute the equitorial radius, angle, and emission time of a photon, we perform a backward ray-tracing from the observer plane. By running the following, we evaluate the source radius, angle, and time within the grid from each lensing bands:
7983

80-
<code> >> python raytracing.py </code>
84+
<code> python raytracing.py </code>
8185

8286
The result will be stored in a HDF5 file that contains source radius, angle, time, as well as the radial component of the four momentum at the equitorial plane, for lensing bands n=0,1,2. The datasets inside the resulting file are:
8387

@@ -96,7 +100,7 @@ This image is produced in the example code:
96100

97101
Once the lensing bands and the rays have been computed, an image can be produced using a defined analytical profile by simply running
98102

99-
<code> >> python radialintensity.py </code>
103+
<code> python radialintensity.py </code>
100104

101105
The datasets inside the resulting file are:
102106

@@ -114,11 +118,11 @@ As the dataset produced after ray tracing contains all the information of the BL
114118

115119
One can also use a precomputed equatorial profile. AART currently implements profiles computed with inoisy. The example includes a test case (<em>inoisy.h5</em>), for which one can simply run by
116120

117-
<code> >> python iImages.py </code>
121+
<code> python iImages.py </code>
118122

119123
or
120124

121-
<code> >> python iMovies.py </code>
125+
<code> python iMovies.py </code>
122126

123127
to produce images or a set of images, respectively. Images can be produced by using a single equatorial profile, i.e., in the mode "stationary," or using the entire history of the equatorial structure, i.e, in the mode "dynamical." When movies are made, the dynamical version is assumed. In both cases, the resulting datasets inside the resulting file are:
124128

@@ -132,7 +136,7 @@ This gif is produced in the example code:
132136

133137
With the images created using radial intensity prifiles, one may then calculate the visibility of the image projected onto a baseline. This function first performs radon transforms of the image at a set of specified angles (radonangles in <em>params.py</em>), and then compute the visibility amplitude by
134138

135-
<code> >> python visamp.py </code>
139+
<code> python visamp.py </code>
136140

137141
This function creates a set of h5 files, one for each basline angle. These files contains the visibility amplitude as well as the frequency (baseline length in G$\lambda$). The resulting datasets inside the resulting file are:
138142

@@ -152,7 +156,7 @@ This image is produced in the example code:
152156

153157
The linear polarization of a given configuration of the magnetic field can be computed by
154158

155-
<code> >> python polarization.py </code>
159+
<code> python polarization.py </code>
156160

157161
The resulting datasets inside the resulting file are:
158162

@@ -179,11 +183,11 @@ The linear polarization of a given configuration of the magnetic field can be co
179183

180184
## References ##
181185

182-
[1] Cardenas-Avendano, A., Zhu, H. & Lupsasca, A. Adaptive Analytical Ray-Tracing of Black Hole Photon Rings.
186+
[1] Cardenas-Avendano, A., Lupsasca, A. & Zhu, H. Adaptive Analytical Ray Tracing of Black Hole Photon Rings. [arXiv:2211.07469](https://arxiv.org/abs/2211.07469)
183187

184-
[2] Gralla, S. E., & Lupsasca, A. (2020). Lensing by Kerr black holes. Physical Review D, 101(4), 044031.(arXiv:1910.12873)
188+
[2] Gralla, S. E., & Lupsasca, A. (2020). Lensing by Kerr black holes. Physical Review D, 101(4), 044031.
185189

186-
[3] Gralla, S. E., & Lupsasca, A. (2020). Null geodesics of the Kerr exterior. Physical Review D, 101(4), 044032.(arXiv:1910.12881)
190+
[3] Gralla, S. E., & Lupsasca, A. (2020). Null geodesics of the Kerr exterior. Physical Review D, 101(4), 044032.
187191

188192
[4] Gralla, S. E., Lupsasca, A., & Marrone, D. P. (2020). The shape of the black hole photon ring: A precise test of strong-field general relativity. Physical Review D, 102(12), 124004.
189193

aart_func/intensity_f.py

Lines changed: 130 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,89 @@
11
from aart_func import *
22
from params import *
33

4-
def gDisk(r,a,lamb):
4+
def Delta(r,a):
55
"""
6-
Calculates the redshift factor for a photon outside the inner-most stable circular orbit(isco) (assume circular orbit)
6+
Calculates the Kerr metric function \Delta(t)
77
:param r: radius of the source
88
:param a: spin of the black hole
9-
:param lamb: angular momentum
9+
"""
10+
return r**2-2*r+a**2
1011

11-
:return: the redshift factor associated with the ray
12+
def PIF(r,a):
13+
"""
14+
Calculates PI(r) (Eq. B6 P1)
15+
:param r: radius of the source
16+
:param a: spin of the black hole
17+
"""
18+
return (r**2+a**2)**2-a**2*Delta(r,a)
19+
20+
def urbar(r,a):
21+
"""
22+
Calculates the r (contravariant) component of the four velocity for radial infall
23+
(Eq. B34b P1)
24+
:param r: radius of the source
25+
:param a: spin of the black hole
26+
"""
27+
return -np.sqrt(2*r*(r**2+a**2))/(r**2)
28+
29+
def Omegabar(r,a):
30+
"""
31+
Calculates the angular velocity of the radial infall
32+
(Eq. B32a P1)
33+
:param r: radius of the source
34+
:param a: spin of the black hole
35+
"""
36+
return (2*a*r)/PIF(r,a)
37+
38+
def Omegahat(r,a,laux):
39+
"""
40+
Calculates the angular velocity of the sub-Keplerian orbit
41+
(Eq. B39 P1)
42+
:param r: radius of the source
43+
:param a: spin of the black hole
44+
"""
45+
return (a+(1-2/r)*(laux-a))/(PIF(r,a)/(r**2)-(2*a*laux)/r)
46+
47+
def uttilde(r, a,urT,OT):
48+
"""
49+
Calculates the t (contravariant) component of the general four velocity
50+
(Eq. B52 P1)
51+
:param r: radius of the source
52+
:param a: spin of the black hole
53+
:param urT: r (contravariant) component of the general four velocity
54+
:param OT: Angular velocity of the general four velocity
55+
"""
56+
return np.sqrt((1 + urT**2*r**2/Delta(r,a))/(1-(r**2+a**2)*OT**2-(2/r)*(1-a*OT)**2))
57+
58+
def Ehat(r,a,laux):
59+
"""
60+
Calculates the orbital energy of the sub-Keplerian flow
61+
(Eq. B44a P1)
62+
:param r: radius of the source
63+
:param a: spin of the black hole
64+
:param laux: sub-Keplerian specific angular momentum
65+
"""
66+
return np.sqrt(Delta(r,a)/(PIF(r,a)/(r**2)-(4*a*laux)/r-(1-2/r)*laux**2))
67+
68+
def nuhat(r,a,laux,Ehataux):
69+
"""
70+
Calculates the radial velocity of the sub-Keplerian flow
71+
(Eq. B45 P1)
72+
:param r: radius of the source
73+
:param a: spin of the black hole
74+
:param laux: sub-Keplerian specific angular momentum
75+
:param Ehataux: sub-Keplerian orbital energy
76+
"""
77+
return r/Delta(r,a)*np.sqrt(np.abs(PIF(r,a)/(r**2)-(4*a*laux)/r-(1-2/r)*laux**2-Delta(r,a)/(Ehataux**2)))
78+
79+
def lhat(r,a):
1280
"""
13-
#Eqns (P4 B7)
14-
return sqrt(r**3 - 3*r**2 + 2*a*r**(3/2))/(r**(3/2) - (lamb- a))
81+
Calculates the rspecific angular momentum of the sub-Keplerian flow
82+
(Eq. B44b P1)
83+
:param r: radius of the source
84+
:param a: spin of the black hole
85+
"""
86+
return sub_kep*(r**2+a**2-2*a*np.sqrt(r))/(np.sqrt(r)*(r-2)+a)
1587

1688
def Rint(r,a,lamb,eta):
1789
"""
@@ -26,75 +98,96 @@ def Rint(r,a,lamb,eta):
2698
#Eqns (P2 5)
2799
return (r**2 + a**2 - a*lamb)**2 - (r**2 - 2*r + a**2)*(eta + (lamb - a)**2)
28100

29-
def gGas(r,b,a,lamb,eta):
101+
def gDisk(r,a,b,lamb,eta):
102+
"""
103+
Calculates the redshift factor for a photon outside the inner-most stable circular orbit(isco) (assume circular orbit)
104+
(Eq. B13 P1)
105+
:param r: radius of the source
106+
:param a: spin of the black hole
107+
:param lamb: angular momentum
108+
:param eta: Carter constant
109+
110+
:return: the redshift factor associated with the ray
111+
"""
112+
113+
OH=Omegahat(r,a,lhat(r,a))
114+
OT=OH+(1-betaphi)*(Omegabar(r,a)-OH)
115+
ur=(1-betar)*urbar(r,a)
116+
ut=uttilde(r,a,ur,OT)
117+
uphi=ut*OT
118+
119+
return 1/(ut*(1-b*np.sign(ur)*sqrt(np.abs(Rint(r,a,lamb,eta)*ur**2))/Delta(r,a)/ut-lamb*uphi/ut))
120+
121+
def gGas(r,a,b,lamb,eta):
30122
"""
31123
Calculates the redshift factor for a photon inside the isco (assume infalling orbit)
124+
(Eq. B13 P1)
32125
:param r: radius of the source
33-
:param b: sign for the redshift
34126
:param a: spin of the black hole
127+
:param b: sign for the redshift
35128
:param lamb: angular momentum
36129
:param eta: carter constant
37130
38131
:return: the redshift factor associated with the ray
39132
"""
40-
#calculate radius of the inner-most stable circular orbit
133+
#Calculate radius of the inner-most stable circular orbit
41134
isco=rms(a)
42135

43-
#Eqns (P2 2)
44-
Delta=r**2 - 2*r + a**2
136+
lms=lhat(isco,a)
137+
OH=Omegahat(r,a,lms)
138+
OT=OH+(1-betaphi)*(Omegabar(r,a)-OH)
45139

46-
#Eqns (P3 B13)
47-
lambe=((isco**2 - 2*a*sqrt(isco) + a**2))/(isco**(3/2) - 2*sqrt(isco) + a)
48-
#Eqns (P3 B12)
49-
H=(2*r - a*lambe)/Delta
140+
Ems=Ehat(isco,a,lms)
141+
urhat=-Delta(r,a)/(r**2)*nuhat(r, a, lms ,Ems)*Ems
142+
ur=urhat+(1-betar)*(urbar(r,a)-urhat)
143+
ut=uttilde(r,a,ur,OT)
144+
uphi=OT*ut
50145

51-
#Eqns (P3 B14)
52-
gamma=sqrt(1 - 2/3 *1/isco)
53-
54-
#Eqns (P3 B9-B11)
55-
ut=gamma*(1 + (2)/r *(1 + H))
56-
uphi=gamma/r**2*(lambe + a*H)
57-
ur=-np.sqrt(2/3/isco)*(isco/r - 1)**(3/2)
58-
#Eqns (P3 B15)
59-
return 1/(ut - uphi*lamb - ur*Delta**(-1)*b*sqrt(Rint(r,a,lamb,eta)))
146+
return 1/(ut*(1-b*np.sign(ur)*sqrt(np.abs(Rint(r,a,lamb,eta)*ur**2))/Delta(r,a)/ut-lamb*uphi/ut))
60147

61148
#calculate the observed brightness for a purely radial profile
62149
def bright_radial(grid,mask,redshift_sign,a,rs,isco,thetao):
63150
"""
64151
Calculate the brightness of a rotationally symmetric disk
152+
(Eq. 50 P1)
65153
:param grid: alpha and beta grid on the observer plane on which we evaluate the observables
66154
:param mask: mask out the lensing band, see lb_f.py for detail
67155
:param redshift_sign: sign of the redshift
68156
:param a: black hole spin
69157
:param rs: source radius
70158
:param isco: radius of the inner-most stable circular orbit
71159
:param thetao: observer inclination
72-
:hidden param profile: radial profile of the intensity
73160
74161
:return: image of a lensed equitorial source with only radial dependence.
75162
"""
76163
alpha = grid[:,0][mask]
77164
beta = grid[:,1][mask]
165+
78166
rs = rs[mask]
167+
79168
lamb,eta = rt.conserved_quantities(alpha,beta,thetao,a)
169+
80170
brightness = np.zeros(rs.shape[0])
81171
redshift_sign = redshift_sign[mask]
82-
brightness[rs>=isco]= gDisk(rs[rs>=isco],a,lamb[rs>=isco])**gfactor*ilp.profile(rs[rs>=isco],a,gammap,mup,sigmap)
83172

84-
brightness[rs<isco]= gGas(rs[rs<isco],redshift_sign[rs<isco],a,lamb[rs<isco],eta[rs<isco])**gfactor*ilp.profile(rs[rs<isco],a,gammap,mup,sigmap)
173+
brightness[rs>=isco]= gDisk(rs[rs>=isco],a,redshift_sign[rs>=isco],lamb[rs>=isco],eta[rs>=isco])**gfactor*ilp.profile(rs[rs>=isco],a,gammap,mup,sigmap)
174+
brightness[rs<isco]= gGas(rs[rs<isco],a,redshift_sign[rs<isco],lamb[rs<isco],eta[rs<isco])**gfactor*ilp.profile(rs[rs<isco],a,gammap,mup,sigmap)
85175

86176
r_p = 1+np.sqrt(1-a**2)
87177
brightness[rs<=r_p] = 0
88178

89179
I = np.zeros(mask.shape)
90180
I[mask] = brightness
181+
91182
return(I)
92183

184+
93185
#calculate the observed brightness for an arbitrary profile, passed in as the interpolation object
94186
#but ignoring the time delay due to lensing
95187
def fast_light(grid,mask,redshift_sign,a,isco,rs,th,interpolation,thetao):
96188
"""
97189
Calculate the black hole image ignoring the time delay due to lensing or geometric effect
190+
(Eq. 116 P1)
98191
:param grid: alpha and beta grid on the observer plane on which we evaluate the observables
99192
:param mask: mask out the lensing band, see lb_f.py for detail
100193
:param redshift_sign: sign of the redshift
@@ -115,12 +208,11 @@ def fast_light(grid,mask,redshift_sign,a,isco,rs,th,interpolation,thetao):
115208
brightness = np.zeros(rs.shape[0])
116209
redshift_sign = redshift_sign[mask]
117210

118-
#Eqs. 60 and 61 in 0706.0622
119-
x_aux=np.sqrt(rs**2+a**2)*np.cos(th)
120-
y_aux=np.sqrt(rs**2+a**2)*np.sin(th)
211+
x_aux=rs*np.cos(th)
212+
y_aux=rs*np.sin(th)
121213

122-
brightness[rs>=isco]= gDisk(rs[rs>=isco],a,lamb[rs>=isco])**gfactor*interpolation(np.vstack([x_aux[rs>=isco],y_aux[rs>=isco]]).T)
123-
brightness[rs<isco]= gGas(rs[rs<isco],redshift_sign[rs<isco],a,lamb[rs<isco],eta[rs<isco])**gfactor*interpolation(np.vstack([x_aux[rs<isco],y_aux[rs<isco]]).T)
214+
brightness[rs>=isco]= gDisk(rs[rs>=isco],a,redshift_sign[rs>=isco],lamb[rs>=isco],eta[rs>=isco])**gfactor*interpolation(np.vstack([x_aux[rs>=isco],y_aux[rs>=isco]]).T)
215+
brightness[rs<isco]= gGas(rs[rs<isco],a,redshift_sign[rs<isco],lamb[rs<isco],eta[rs<isco])**gfactor*interpolation(np.vstack([x_aux[rs<isco],y_aux[rs<isco]]).T)
124216

125217
r_p = 1+np.sqrt(1-a**2)
126218
brightness[rs<=r_p] = 0
@@ -133,6 +225,8 @@ def fast_light(grid,mask,redshift_sign,a,isco,rs,th,interpolation,thetao):
133225
def slow_light(grid,mask,redshift_sign,a,isco,rs,th,ts,interpolation,thetao):
134226
"""
135227
Calculate the black hole image including the time delay due to lensing and geometric effect
228+
(Eq. 50 P1)
229+
136230
:param grid: alpha and beta grid on the observer plane on which we evaluate the observables
137231
:param mask: mask out the lensing band, see lb_f.py for detail
138232
:param redshift_sign: sign of the redshift
@@ -155,12 +249,11 @@ def slow_light(grid,mask,redshift_sign,a,isco,rs,th,ts,interpolation,thetao):
155249
brightness = np.zeros(rs.shape[0])
156250
redshift_sign = redshift_sign[mask]
157251

158-
#Eqs. 60 and 61 in 0706.0622
159-
x_aux=np.sqrt(rs**2+a**2)*np.cos(th)
160-
y_aux=np.sqrt(rs**2+a**2)*np.sin(th)
252+
x_aux=rs*np.cos(th)
253+
y_aux=rs*np.sin(th)
161254

162-
brightness[rs>=isco]= gDisk(rs[rs>=isco],a,lamb[rs>=isco])**gfactor*interpolation(np.vstack([ts[rs>=isco],x_aux[rs>=isco],y_aux[rs>=isco]]).T)
163-
brightness[rs<isco]= gGas(rs[rs<isco],redshift_sign[rs<isco],a,lamb[rs<isco],eta[rs<isco])**gfactor*interpolation(np.vstack([ts[rs<isco],x_aux[rs<isco],y_aux[rs<isco]]).T)
255+
brightness[rs>=isco]= gDisk(rs[rs>=isco],a,redshift_sign[rs>=isco],lamb[rs>=isco],eta[rs>=isco])**gfactor*interpolation(np.vstack([ts[rs>=isco],x_aux[rs>=isco],y_aux[rs>=isco]]).T)
256+
brightness[rs<isco]= gGas(rs[rs<isco],a,redshift_sign[rs<isco],lamb[rs<isco],eta[rs<isco])**gfactor*interpolation(np.vstack([ts[rs<isco],x_aux[rs<isco],y_aux[rs<isco]]).T)
164257

165258
r_p = 1+np.sqrt(1-a**2)
166259
brightness[rs<=r_p] = 0

aart_func/misc.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ def cbrt(x):
1313
def rms(a):
1414
'''
1515
ISCO value
16+
(Eq. B16 P1)
1617
:param a: BH spin
1718
'''
1819
Z1=1 + (1 - a**2)**(1/3) *((1 + a)**(1/3) + (1 - a)**(1/3))

0 commit comments

Comments
 (0)