1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
import numpy as np
import scipy.interpolate as interp
from scipy.integrate import odeint
def calc_null_curves(times, spatial_coords, gXX, gXt, gtt):
"""
Compute null curves along a given axis.
Shoot a null ray from each point in spatial_coords, in the positive and
negative direction and compute its trajectory.
:param array_like times: 1D array of coordinate times at which the spacetime
curvature is provided
:param array_like spatial_coords: 1D array of spatial coordinates
:param array_like gXX: 2D array containing the values of the XX component
of the spacetime metric, where X is the spatial
coordinate along which the rays are traced.
gXX[i, j] is the value at spacetime point
(t=times[i], X=spatial_coords[j]).
:param array_like gXt: same as gXX, but for the Xt component of the metric
:param array_like gtt: same as gXX, but for the tt component of the metric
:return: tuple containing two 2D arrays with, respectively, the positive and
negative-direction rays. rays[i, j] contains the X-coordinate of
the ray shot from (t=times[0], X=spatial_coords[i]) at time
t=times[j]
"""
gXX_interp = interp.RectBivariateSpline(times, spatial_coords, gXX)
gXt_interp = interp.RectBivariateSpline(times, spatial_coords, gXt)
gtt_interp = interp.RectBivariateSpline(times, spatial_coords, gtt)
def _dXdt(coord, t, sign,
coord_min = spatial_coords[0], coord_max = spatial_coords[-1],
gXX = gXX_interp, gtt = gtt_interp, gXt = gXt_interp):
if coord <= coord_min or coord >= coord_max:
return float('nan')
gXt_val = gXt(t, coord)
gXX_val = gXX(t, coord)
gtt_val = gtt(t, coord)
return ((-gXt_val + sign * np.sqrt((gXt_val ** 2) - gtt_val * gXX_val)) / gXX_val).flatten()[0]
rays_pos = np.empty((spatial_coords.shape[0], times.shape[0]))
rays_neg = np.empty_like(rays_pos)
for j, X0 in enumerate(spatial_coords):
for tgt, sign in ((rays_pos, 1.0), (rays_neg, -1.0)):
ray = odeint(_dXdt, X0, times, (sign,))[:, 0]
# clip the rays to the integration area
k = 0
while np.isnan(ray[k]):
k += 1
while k > 0:
ray[k - 1] = ray[k]
k -= 1
k = ray.shape[0] - 1
while np.isnan(ray[k]):
k -= 1
while k < ray.shape[0] - 1:
ray[k + 1] = ray[k]
k += 1
tgt[j] = ray
return (rays_pos, rays_neg)
def calc_null_coordinates(times, spatial_coords, u_rays, v_rays,
gXX, gXt, gtt):
"""
Compute double-null coordinates (u, v) as functions of
position and time.
:param array_like times: 1D array of coordinate times at which the spacetime
curvature is provided
:param array_like spatial_coords: 1D array of spatial coordinates
:param array_like u_rays: 1D array assigning the values of u on the initial
time slice. u_rays[i] is the value of u at
X=spatial_coords[i].
:param array_like v_rays: same as u_rays, but for v.
:param array_like gXX: 2D array containing the values of the XX component
of the spacetime metric, where X is the spatial
coordinate along which the rays are traced.
gXX[i, j] is the value at spacetime point
(t=times[i], X=spatial_coords[j]).
:param array_like gXt: same as gXX, but for the Xt component of the metric
:param array_like gtt: same as gXX, but for the tt component of the metric
:return: tuple containing two 2D arrays with, respectively, values of u and
v as functions of t and X. u/v[i, j] is the value of u/v at
t=times[i], X=spatial_coords[j].
"""
X_of_ut, X_of_vt = calc_null_curves(times, spatial_coords, gXX, gXt, gtt)
u_of_tx = np.empty((times.shape[0], spatial_coords.shape[0]))
v_of_tx = np.empty_like(u_of_tx)
for i, t in enumerate(times):
Xu = X_of_ut[:, i]
Xv = X_of_vt[:, i]
u_of_tx[i] = interp.interp1d(Xu, u_rays)(spatial_coords)
v_of_tx[i] = interp.interp1d(Xv, v_rays)(spatial_coords)
return (u_of_tx, v_of_tx)
|