tabsim 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tabsim/__init__.py +0 -0
- tabsim/config.py +904 -0
- tabsim/dask/__init__.py +0 -0
- tabsim/dask/coordinates.py +469 -0
- tabsim/dask/extras.py +60 -0
- tabsim/dask/interferometry.py +572 -0
- tabsim/dask/observation.py +969 -0
- tabsim/data/EDA2.itrf.txt +256 -0
- tabsim/data/MWA.itrf.txt +128 -0
- tabsim/data/MeerKAT.itrf.txt +64 -0
- tabsim/data/__init__.py +0 -0
- tabsim/data/aux_data/calibrator.skymodel +2 -0
- tabsim/data/aux_data/norad_satellite.rfimodel +61711 -0
- tabsim/data/aux_data/satellite.ole +3 -0
- tabsim/data/aux_data/satellite.rfimodel +3 -0
- tabsim/data/aux_data/stationary.loc +4 -0
- tabsim/data/aux_data/stationary.rfimodel +4 -0
- tabsim/data/config_files/sim_config_base.yaml +172 -0
- tabsim/data/config_files/tab_config_base.yaml +86 -0
- tabsim/jax/__init__.py +0 -0
- tabsim/jax/coordinates.py +1082 -0
- tabsim/jax/interferometry.py +667 -0
- tabsim/jax/utils.py +90 -0
- tabsim/plot.py +323 -0
- tabsim/scripts/__init__.py +1 -0
- tabsim/scripts/ast_region.py +56 -0
- tabsim/scripts/flag_data.py +195 -0
- tabsim/scripts/sim_vis.py +136 -0
- tabsim/scripts/tle_sat_region.py +191 -0
- tabsim/sky.py +137 -0
- tabsim/tle.py +753 -0
- tabsim/tools.py +111 -0
- tabsim/write.py +715 -0
- tabsim-0.0.1.dist-info/METADATA +991 -0
- tabsim-0.0.1.dist-info/RECORD +39 -0
- tabsim-0.0.1.dist-info/WHEEL +5 -0
- tabsim-0.0.1.dist-info/entry_points.txt +5 -0
- tabsim-0.0.1.dist-info/licenses/LICENSE +674 -0
- tabsim-0.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,572 @@
|
|
|
1
|
+
import dask.array as da
|
|
2
|
+
import numpy as np
|
|
3
|
+
import xarray as xr
|
|
4
|
+
from dask.delayed import delayed
|
|
5
|
+
from dask.array.core import Array
|
|
6
|
+
from tabsim.jax import interferometry as itf
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def astro_vis(sources: Array, uvw: Array, lmn: Array, freqs: Array) -> Array:
|
|
10
|
+
"""Calculate visibilities from sources, uvw, lmn, and freqs.
|
|
11
|
+
|
|
12
|
+
Parameters:
|
|
13
|
+
-----------
|
|
14
|
+
sources: Array (n_src, n_time, n_freq)
|
|
15
|
+
Array of point source intensities in Jy.
|
|
16
|
+
uvw: Array (ntime, n_bl, 3)
|
|
17
|
+
(u,v,w) coordinates of each baseline.
|
|
18
|
+
lmn: Array (n_src, 3)
|
|
19
|
+
(l,m,n) coordinate of each source.
|
|
20
|
+
freqs: Array (n_freq,)
|
|
21
|
+
Frequencies in Hz.
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
--------
|
|
25
|
+
vis: Array (n_time, n_bl, n_freq)
|
|
26
|
+
"""
|
|
27
|
+
n_time, n_bl = uvw.shape[:2]
|
|
28
|
+
n_freq = freqs.shape[0]
|
|
29
|
+
|
|
30
|
+
time_chunk, bl_chunk = uvw.chunksize[:2]
|
|
31
|
+
freq_chunk = freqs.chunksize[0]
|
|
32
|
+
|
|
33
|
+
src_n_time = sources.shape[1]
|
|
34
|
+
if src_n_time != n_time and src_n_time != 1:
|
|
35
|
+
ValueError(
|
|
36
|
+
"The size of the time dimension for the astronomical sources must be n_time_fine or 1."
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
t = "time" if src_n_time is n_time else "time1"
|
|
40
|
+
I = {"I": (["src", f"{t}", "freq"], sources)}
|
|
41
|
+
|
|
42
|
+
input = xr.Dataset(
|
|
43
|
+
{
|
|
44
|
+
**I,
|
|
45
|
+
"uvw": (["time", "bl", "space"], uvw),
|
|
46
|
+
"lmn": (["src", "space"], lmn),
|
|
47
|
+
"freqs": (["freq"], freqs),
|
|
48
|
+
}
|
|
49
|
+
)
|
|
50
|
+
output = xr.Dataset(
|
|
51
|
+
{
|
|
52
|
+
"vis": (
|
|
53
|
+
["time", "bl", "freq"],
|
|
54
|
+
da.zeros(
|
|
55
|
+
shape=(n_time, n_bl, n_freq),
|
|
56
|
+
chunks=(time_chunk, bl_chunk, freq_chunk),
|
|
57
|
+
dtype=complex,
|
|
58
|
+
),
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
def _astro_vis(ds):
|
|
64
|
+
vis = delayed(itf.astro_vis)(
|
|
65
|
+
ds.I.data, ds.uvw.data, ds.lmn.data, ds.freqs.data
|
|
66
|
+
).compute()
|
|
67
|
+
ds_out = xr.Dataset({"vis": (["time", "bl", "freq"], vis)})
|
|
68
|
+
return ds_out
|
|
69
|
+
|
|
70
|
+
ds = xr.map_blocks(_astro_vis, input, template=output)
|
|
71
|
+
|
|
72
|
+
return ds.vis.data
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def astro_vis_gauss(
|
|
76
|
+
sources: Array,
|
|
77
|
+
major: Array,
|
|
78
|
+
minor: Array,
|
|
79
|
+
pos_angle: Array,
|
|
80
|
+
uvw: Array,
|
|
81
|
+
lmn: Array,
|
|
82
|
+
freqs: Array,
|
|
83
|
+
) -> Array:
|
|
84
|
+
"""Calculate visibilities from sources, uvw, lmn, and freqs.
|
|
85
|
+
|
|
86
|
+
Parameters:
|
|
87
|
+
-----------
|
|
88
|
+
sources: Array (n_src, n_time, n_freq)
|
|
89
|
+
Array of point source intensities in Jy.
|
|
90
|
+
shapes: array_like (n_src,)
|
|
91
|
+
Array of standard deviations of the gaussian shape sources. These are
|
|
92
|
+
assumed to be circular gaussians for now.
|
|
93
|
+
uvw: Array (ntime, n_bl, 3)
|
|
94
|
+
(u,v,w) coordinates of each baseline.
|
|
95
|
+
lmn: Array (n_src, 3)
|
|
96
|
+
(l,m,n) coordinate of each source.
|
|
97
|
+
freqs: Array (n_freq,)
|
|
98
|
+
Frequencies in Hz.
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
--------
|
|
102
|
+
vis: Array (n_time, n_bl, n_freq)
|
|
103
|
+
"""
|
|
104
|
+
n_time, n_bl = uvw.shape[:2]
|
|
105
|
+
n_freq = freqs.shape[0]
|
|
106
|
+
|
|
107
|
+
time_chunk, bl_chunk = uvw.chunksize[:2]
|
|
108
|
+
freq_chunk = freqs.chunksize[0]
|
|
109
|
+
|
|
110
|
+
input = xr.Dataset(
|
|
111
|
+
{
|
|
112
|
+
"I": (["src", "time", "freq"], sources),
|
|
113
|
+
"major": (["src"], major),
|
|
114
|
+
"minor": (["src"], minor),
|
|
115
|
+
"pos_angle": (["src"], pos_angle),
|
|
116
|
+
"uvw": (["time", "bl", "space"], uvw),
|
|
117
|
+
"lmn": (["src", "space"], lmn),
|
|
118
|
+
"freqs": (["freq"], freqs),
|
|
119
|
+
}
|
|
120
|
+
)
|
|
121
|
+
output = xr.Dataset(
|
|
122
|
+
{
|
|
123
|
+
"vis": (
|
|
124
|
+
["time", "bl", "freq"],
|
|
125
|
+
da.zeros(
|
|
126
|
+
shape=(n_time, n_bl, n_freq),
|
|
127
|
+
chunks=(time_chunk, bl_chunk, freq_chunk),
|
|
128
|
+
dtype=complex,
|
|
129
|
+
),
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
def _astro_vis_gauss(ds):
|
|
135
|
+
vis = delayed(itf.astro_vis_gauss)(
|
|
136
|
+
ds.I.data,
|
|
137
|
+
ds.major.data,
|
|
138
|
+
ds.minor.data,
|
|
139
|
+
ds.pos_angle.data,
|
|
140
|
+
ds.uvw.data,
|
|
141
|
+
ds.lmn.data,
|
|
142
|
+
ds.freqs.data,
|
|
143
|
+
).compute()
|
|
144
|
+
ds_out = xr.Dataset({"vis": (["time", "bl", "freq"], vis)})
|
|
145
|
+
return ds_out
|
|
146
|
+
|
|
147
|
+
ds = xr.map_blocks(_astro_vis_gauss, input, template=output)
|
|
148
|
+
|
|
149
|
+
return ds.vis.data
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def astro_vis_exp(
|
|
153
|
+
sources: Array, shapes: Array, uvw: Array, lmn: Array, freqs: Array
|
|
154
|
+
) -> Array:
|
|
155
|
+
"""Calculate visibilities from sources, uvw, lmn, and freqs.
|
|
156
|
+
|
|
157
|
+
Parameters:
|
|
158
|
+
-----------
|
|
159
|
+
sources: Array (n_src, n_time, n_freq)
|
|
160
|
+
Array of point source intensities in Jy.
|
|
161
|
+
shapes: array_like (n_src,)
|
|
162
|
+
Array of shape parameters for the exp sources. These are
|
|
163
|
+
assumed to be circular.
|
|
164
|
+
uvw: Array (ntime, n_bl, 3)
|
|
165
|
+
(u,v,w) coordinates of each baseline.
|
|
166
|
+
lmn: Array (n_src, 3)
|
|
167
|
+
(l,m,n) coordinate of each source.
|
|
168
|
+
freqs: Array (n_freq,)
|
|
169
|
+
Frequencies in Hz.
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
--------
|
|
173
|
+
vis: Array (n_time, n_bl, n_freq)
|
|
174
|
+
"""
|
|
175
|
+
n_time, n_bl = uvw.shape[:2]
|
|
176
|
+
n_freq = freqs.shape[0]
|
|
177
|
+
|
|
178
|
+
time_chunk, bl_chunk = uvw.chunksize[:2]
|
|
179
|
+
freq_chunk = freqs.chunksize[0]
|
|
180
|
+
|
|
181
|
+
input = xr.Dataset(
|
|
182
|
+
{
|
|
183
|
+
"I": (["src", "time", "freq"], sources),
|
|
184
|
+
"sigmas": (["src"], shapes),
|
|
185
|
+
"uvw": (["time", "bl", "space"], uvw),
|
|
186
|
+
"lmn": (["src", "space"], lmn),
|
|
187
|
+
"freqs": (["freq"], freqs),
|
|
188
|
+
}
|
|
189
|
+
)
|
|
190
|
+
output = xr.Dataset(
|
|
191
|
+
{
|
|
192
|
+
"vis": (
|
|
193
|
+
["time", "bl", "freq"],
|
|
194
|
+
da.zeros(
|
|
195
|
+
shape=(n_time, n_bl, n_freq),
|
|
196
|
+
chunks=(time_chunk, bl_chunk, freq_chunk),
|
|
197
|
+
dtype=complex,
|
|
198
|
+
),
|
|
199
|
+
)
|
|
200
|
+
}
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
def _astro_vis_exp(ds):
|
|
204
|
+
vis = delayed(itf.astro_vis_exp)(
|
|
205
|
+
ds.I.data, ds.sigmas.data, ds.uvw.data, ds.lmn.data, ds.freqs.data
|
|
206
|
+
).compute()
|
|
207
|
+
ds_out = xr.Dataset({"vis": (["time", "bl", "freq"], vis)})
|
|
208
|
+
return ds_out
|
|
209
|
+
|
|
210
|
+
ds = xr.map_blocks(_astro_vis_exp, input, template=output)
|
|
211
|
+
|
|
212
|
+
return ds.vis.data
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def rfi_vis(
|
|
216
|
+
app_amplitude: Array,
|
|
217
|
+
c_distances: Array,
|
|
218
|
+
freqs: Array,
|
|
219
|
+
a1: Array,
|
|
220
|
+
a2: Array,
|
|
221
|
+
) -> Array:
|
|
222
|
+
"""Calculate visibilities from sources, uvw, lmn, and freqs.
|
|
223
|
+
|
|
224
|
+
Parameters:
|
|
225
|
+
-----------
|
|
226
|
+
app_amplitude: Array (n_src, n_time, n_int, n_ant, n_freq)
|
|
227
|
+
Apparent amplitude of the sources at each antenna.
|
|
228
|
+
c_distances: Array (n_src, n_time, n_int, n_ant)
|
|
229
|
+
The phase corrected distances between the rfi sources and the antennas in metres.
|
|
230
|
+
freqs: Array (n_freq,)
|
|
231
|
+
Frequencies in Hz.
|
|
232
|
+
a1: Array (n_bl,)
|
|
233
|
+
Antenna 1 indexes, between 0 and n_ant-1.
|
|
234
|
+
a2: Array (n_bl,)
|
|
235
|
+
Antenna 2 indexes, between 0 and n_ant-1.
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
--------
|
|
239
|
+
vis: Array (n_time, n_bl, n_freq)
|
|
240
|
+
"""
|
|
241
|
+
n_time = app_amplitude.shape[1]
|
|
242
|
+
n_freq = freqs.shape[0]
|
|
243
|
+
n_bl = a1.shape[0]
|
|
244
|
+
|
|
245
|
+
time_chunk = app_amplitude.chunksize[1]
|
|
246
|
+
freq_chunk = freqs.chunksize[0]
|
|
247
|
+
bl_chunk = a1.chunksize[0]
|
|
248
|
+
|
|
249
|
+
input = xr.Dataset(
|
|
250
|
+
{
|
|
251
|
+
"app_amplitude": (["src", "time", "int", "ant", "freq"], app_amplitude),
|
|
252
|
+
"c_distances": (["src", "time", "int", "ant"], c_distances),
|
|
253
|
+
"freqs": (["freq"], freqs),
|
|
254
|
+
"a1": (["bl"], a1),
|
|
255
|
+
"a2": (["bl"], a2),
|
|
256
|
+
}
|
|
257
|
+
)
|
|
258
|
+
output = xr.Dataset(
|
|
259
|
+
{
|
|
260
|
+
"vis": (
|
|
261
|
+
["time", "bl", "freq"],
|
|
262
|
+
da.zeros(
|
|
263
|
+
shape=(n_time, n_bl, n_freq),
|
|
264
|
+
chunks=(time_chunk, bl_chunk, freq_chunk),
|
|
265
|
+
dtype=complex,
|
|
266
|
+
),
|
|
267
|
+
)
|
|
268
|
+
}
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
def _rfi_vis(ds):
|
|
272
|
+
vis = delayed(itf.rfi_vis)(
|
|
273
|
+
ds.app_amplitude.data,
|
|
274
|
+
ds.c_distances.data,
|
|
275
|
+
ds.freqs.data,
|
|
276
|
+
ds.a1.data,
|
|
277
|
+
ds.a2.data,
|
|
278
|
+
).compute()
|
|
279
|
+
ds_out = xr.Dataset({"vis": (["time", "bl", "freq"], vis)})
|
|
280
|
+
return ds_out
|
|
281
|
+
|
|
282
|
+
ds = xr.map_blocks(_rfi_vis, input, template=output)
|
|
283
|
+
|
|
284
|
+
return ds.vis.data
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def ants_to_bl(G: Array, a1: Array, a2: Array) -> Array:
|
|
288
|
+
n_time, _, n_freq = G.shape
|
|
289
|
+
n_bl = a1.shape[0]
|
|
290
|
+
|
|
291
|
+
time_chunk, _, freq_chunk = G.chunksize
|
|
292
|
+
bl_chunk = a1.chunksize[0]
|
|
293
|
+
|
|
294
|
+
input = xr.Dataset(
|
|
295
|
+
{"G": (["time", "ant", "freq"], G), "a1": (["bl"], a1), "a2": (["bl"], a2)}
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
output = xr.Dataset(
|
|
299
|
+
{
|
|
300
|
+
"G_bl": (
|
|
301
|
+
["time", "bl", "freq"],
|
|
302
|
+
da.zeros(
|
|
303
|
+
(n_time, n_bl, n_freq), chunks=(time_chunk, bl_chunk, freq_chunk)
|
|
304
|
+
),
|
|
305
|
+
)
|
|
306
|
+
}
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
def _ants_to_bl(ds):
|
|
310
|
+
G_bl = delayed(itf.ants_to_bl)(ds.G.data, ds.a1.data, ds.a2.data).compute()
|
|
311
|
+
ds_out = xr.Dataset({"G_bl": (["time", "bl", "freq"], G_bl)})
|
|
312
|
+
return ds_out
|
|
313
|
+
|
|
314
|
+
ds = xr.map_blocks(_ants_to_bl, input, template=output)
|
|
315
|
+
|
|
316
|
+
return ds.G_bl.data
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
ants_to_bl.__doc__ = itf.ants_to_bl.__doc__
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
def airy_beam(theta, freqs, dish_d):
|
|
323
|
+
n_src, n_time, n_ant = theta.shape
|
|
324
|
+
n_freq = freqs.shape[0]
|
|
325
|
+
|
|
326
|
+
src_chunk, time_chunk, ant_chunk = theta.chunksize
|
|
327
|
+
freq_chunk = freqs.chunksize[0]
|
|
328
|
+
|
|
329
|
+
input = xr.Dataset(
|
|
330
|
+
{
|
|
331
|
+
"theta": (["src", "time", "ant"], theta),
|
|
332
|
+
"freqs": (["freq"], freqs),
|
|
333
|
+
"dish_d": (["space_0"], da.from_array([dish_d])),
|
|
334
|
+
}
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
output = xr.Dataset(
|
|
338
|
+
{
|
|
339
|
+
"beam": (
|
|
340
|
+
["src", "time", "ant", "freq"],
|
|
341
|
+
da.zeros(
|
|
342
|
+
(n_src, n_time, n_ant, n_freq),
|
|
343
|
+
chunks=(src_chunk, time_chunk, ant_chunk, freq_chunk),
|
|
344
|
+
),
|
|
345
|
+
)
|
|
346
|
+
}
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
def _airy_beam(ds):
|
|
350
|
+
beam = delayed(itf.airy_beam)(
|
|
351
|
+
ds.theta.data, ds.freqs.data, ds.dish_d.data
|
|
352
|
+
).compute()
|
|
353
|
+
ds_out = xr.Dataset({"beam": (["src", "time", "ant", "freq"], beam)})
|
|
354
|
+
return ds_out
|
|
355
|
+
|
|
356
|
+
ds = xr.map_blocks(_airy_beam, input, template=output)
|
|
357
|
+
|
|
358
|
+
return ds.beam.data
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
airy_beam.__doc__ = itf.airy_beam.__doc__
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
def Pv_to_Sv(Pv, d):
|
|
365
|
+
n_src, _, n_freq = Pv.shape
|
|
366
|
+
n_time, n_ant = d.shape[1:]
|
|
367
|
+
|
|
368
|
+
src_chunk, _, freq_chunk = Pv.chunksize
|
|
369
|
+
time_chunk, ant_chunk = d.chunksize[1:]
|
|
370
|
+
|
|
371
|
+
input = xr.Dataset(
|
|
372
|
+
{"Pv": (["src", "time", "freq"], Pv), "d": (["src", "time", "ant"], d)}
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
output = xr.Dataset(
|
|
376
|
+
{
|
|
377
|
+
"Sv": (
|
|
378
|
+
["src", "time", "ant", "freq"],
|
|
379
|
+
da.zeros(
|
|
380
|
+
(n_src, n_time, n_ant, n_freq),
|
|
381
|
+
chunks=(src_chunk, time_chunk, ant_chunk, freq_chunk),
|
|
382
|
+
),
|
|
383
|
+
)
|
|
384
|
+
}
|
|
385
|
+
)
|
|
386
|
+
|
|
387
|
+
def _Pv_to_Sv(ds):
|
|
388
|
+
Sv = delayed(itf.Pv_to_Sv)(ds.Pv.data, ds.d.data).compute()
|
|
389
|
+
ds_out = xr.Dataset({"Sv": (["src", "time", "ant", "freq"], Sv)})
|
|
390
|
+
return ds_out
|
|
391
|
+
|
|
392
|
+
ds = xr.map_blocks(_Pv_to_Sv, input, template=output)
|
|
393
|
+
|
|
394
|
+
return ds.Sv.data
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
Pv_to_Sv.__doc__ = itf.Pv_to_Sv.__doc__
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
def add_noise(vis: Array, noise_std: float, key: int):
|
|
401
|
+
rng = np.random.default_rng(key)
|
|
402
|
+
noise = rng.normal(0, noise_std, size=vis.shape) + 1.0j * rng.normal(
|
|
403
|
+
0, noise_std, size=vis.shape
|
|
404
|
+
)
|
|
405
|
+
return vis + noise, noise
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
def SEFD_to_noise_std(SEFD, chan_width, t_int):
|
|
409
|
+
noise_std = SEFD / da.sqrt(chan_width * t_int)
|
|
410
|
+
return noise_std
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
# def int_sample_times(times, n_int_samples, int_time):
|
|
414
|
+
# times_fine = da.from_array(
|
|
415
|
+
# itf.int_sample_times(times, n_int_samples, int_time), chunks=times.chunksize
|
|
416
|
+
# )
|
|
417
|
+
# return times_fine
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
def int_sample_times(times, n_int_samples: int, int_time: float = None):
|
|
421
|
+
|
|
422
|
+
n_time = len(times)
|
|
423
|
+
time_range = times[-1] - times[0]
|
|
424
|
+
int_time = time_range / (n_time - 1) if not int_time else int_time
|
|
425
|
+
n_time_fine = n_time * n_int_samples
|
|
426
|
+
times_fine = da.linspace(
|
|
427
|
+
-int_time / 2, time_range + int_time / 2, n_time_fine, endpoint=False
|
|
428
|
+
)
|
|
429
|
+
|
|
430
|
+
return times[0] + int_time / (2 * n_int_samples) + times_fine
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
def generate_gains(
|
|
434
|
+
G0_mean: float,
|
|
435
|
+
G0_std: float,
|
|
436
|
+
Gt_std_amp: float,
|
|
437
|
+
Gt_std_phase: float,
|
|
438
|
+
times: np.ndarray,
|
|
439
|
+
n_ant: int,
|
|
440
|
+
n_freq: int,
|
|
441
|
+
random_seed: int,
|
|
442
|
+
) -> Array:
|
|
443
|
+
rng = np.random.default_rng(random_seed)
|
|
444
|
+
times = times[:, None, None] - times[0]
|
|
445
|
+
|
|
446
|
+
# Generate the initial gain values
|
|
447
|
+
G0 = G0_mean * da.exp(
|
|
448
|
+
1.0j * rng.uniform(low=-np.pi / 2, high=np.pi / 2, size=(1, n_ant, n_freq))
|
|
449
|
+
) + (
|
|
450
|
+
rng.normal(scale=G0_std, size=(1, n_ant, n_freq))
|
|
451
|
+
+ 1.0j * rng.normal(scale=G0_std, size=(1, n_ant, n_freq))
|
|
452
|
+
)
|
|
453
|
+
|
|
454
|
+
# Generate the gain variations
|
|
455
|
+
gain_amp = rng.normal(scale=Gt_std_amp, size=(1, n_ant, 1)) * times
|
|
456
|
+
gain_phase = rng.normal(scale=Gt_std_phase, size=(1, n_ant, 1)) * times
|
|
457
|
+
# Generate the gain time series
|
|
458
|
+
gain_ants = G0 + gain_amp * da.exp(1.0j * gain_phase)
|
|
459
|
+
# Set the gain on the last antenna to have zero phase (reference antenna)
|
|
460
|
+
gain_ants[:, -1, :] = da.abs(gain_ants[:, -1, :])
|
|
461
|
+
|
|
462
|
+
return gain_ants
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
def generate_fourier_gains(
|
|
466
|
+
G0_mean: float,
|
|
467
|
+
G0_std: float,
|
|
468
|
+
Gt_std_amp: float,
|
|
469
|
+
Gt_std_phase: float,
|
|
470
|
+
Gt_corr_amp: float,
|
|
471
|
+
Gt_corr_phase: float,
|
|
472
|
+
times_jd: np.ndarray,
|
|
473
|
+
n_ant: int,
|
|
474
|
+
n_freq: int,
|
|
475
|
+
random_seed: int,
|
|
476
|
+
) -> Array:
|
|
477
|
+
|
|
478
|
+
rng = np.random.default_rng(random_seed)
|
|
479
|
+
times = times_jd[None, :, None, None] * 24
|
|
480
|
+
|
|
481
|
+
# Generate the initial gain values
|
|
482
|
+
G0 = G0_mean * da.exp(
|
|
483
|
+
1.0j * rng.uniform(low=-np.pi / 2, high=np.pi / 2, size=(1, n_ant, n_freq))
|
|
484
|
+
) + (
|
|
485
|
+
rng.normal(scale=G0_std / 100, size=(1, n_ant, n_freq))
|
|
486
|
+
+ 1.0j * rng.normal(scale=G0_std / 100, size=(1, n_ant, n_freq))
|
|
487
|
+
)
|
|
488
|
+
|
|
489
|
+
N = 1000
|
|
490
|
+
mode_size = (N, 1, n_ant, 1)
|
|
491
|
+
|
|
492
|
+
# Generate the gain variations
|
|
493
|
+
gain_amp = np.mean(
|
|
494
|
+
rng.normal(scale=Gt_std_amp / 100, size=mode_size)
|
|
495
|
+
* np.cos(
|
|
496
|
+
2
|
|
497
|
+
* np.pi
|
|
498
|
+
* rng.normal(scale=1 / (2 * np.pi * Gt_corr_amp), size=mode_size)
|
|
499
|
+
* times
|
|
500
|
+
+ rng.uniform(low=0.0, high=2 * np.pi, size=mode_size)
|
|
501
|
+
),
|
|
502
|
+
axis=0,
|
|
503
|
+
) * np.sqrt(2 * N)
|
|
504
|
+
gain_phase = np.mean(
|
|
505
|
+
rng.normal(scale=np.deg2rad(Gt_std_phase), size=mode_size)
|
|
506
|
+
* np.cos(
|
|
507
|
+
2
|
|
508
|
+
* np.pi
|
|
509
|
+
* rng.normal(scale=1 / (2 * np.pi * Gt_corr_phase), size=mode_size)
|
|
510
|
+
* times
|
|
511
|
+
+ rng.uniform(low=0.0, high=2 * np.pi, size=mode_size)
|
|
512
|
+
),
|
|
513
|
+
axis=0,
|
|
514
|
+
) * np.sqrt(2 * N)
|
|
515
|
+
# Generate the gain time series
|
|
516
|
+
gain_ants = G0 + gain_amp * da.exp(1.0j * gain_phase)
|
|
517
|
+
# Set the gain on the last antenna to have zero phase (reference antenna)
|
|
518
|
+
gain_ants[:, -1, :] = da.abs(gain_ants[:, -1, :])
|
|
519
|
+
|
|
520
|
+
return gain_ants
|
|
521
|
+
|
|
522
|
+
|
|
523
|
+
def apply_gains(
|
|
524
|
+
vis_ast: Array,
|
|
525
|
+
vis_rfi: Array,
|
|
526
|
+
gains: Array,
|
|
527
|
+
a1: Array,
|
|
528
|
+
a2: Array,
|
|
529
|
+
) -> Array:
|
|
530
|
+
n_time, n_bl, n_freq = vis_ast.shape
|
|
531
|
+
|
|
532
|
+
time_chunk, bl_chunk, freq_chunk = vis_ast.chunksize
|
|
533
|
+
|
|
534
|
+
input = xr.Dataset(
|
|
535
|
+
{
|
|
536
|
+
"vis_ast": (["time", "bl", "freq"], vis_ast),
|
|
537
|
+
"vis_rfi": (["time", "bl", "freq"], vis_rfi),
|
|
538
|
+
"gains": (["time", "ant", "freq"], gains),
|
|
539
|
+
"a1": (["bl"], a1),
|
|
540
|
+
"a2": (["bl"], a2),
|
|
541
|
+
}
|
|
542
|
+
)
|
|
543
|
+
|
|
544
|
+
output = xr.Dataset(
|
|
545
|
+
{
|
|
546
|
+
"vis_obs": (
|
|
547
|
+
["time", "bl", "freq"],
|
|
548
|
+
da.zeros(
|
|
549
|
+
(n_time, n_bl, n_freq),
|
|
550
|
+
chunks=(time_chunk, bl_chunk, freq_chunk),
|
|
551
|
+
dtype=vis_ast.dtype,
|
|
552
|
+
),
|
|
553
|
+
)
|
|
554
|
+
}
|
|
555
|
+
)
|
|
556
|
+
|
|
557
|
+
def _apply_gains(ds):
|
|
558
|
+
vis_obs = delayed(itf.apply_gains)(
|
|
559
|
+
ds.vis_ast.data, ds.vis_rfi.data, ds.gains.data, ds.a1.data, ds.a2.data
|
|
560
|
+
).compute()
|
|
561
|
+
ds_out = xr.Dataset({"vis_obs": (["time", "bl", "freq"], vis_obs)})
|
|
562
|
+
return ds_out
|
|
563
|
+
|
|
564
|
+
ds = xr.map_blocks(_apply_gains, input, template=output)
|
|
565
|
+
|
|
566
|
+
return ds.vis_obs.data
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
def time_avg(vis, n_int_samples):
|
|
570
|
+
return da.mean(
|
|
571
|
+
da.reshape(vis, (-1, n_int_samples, vis.shape[1], vis.shape[2])), axis=1
|
|
572
|
+
)
|