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.
File without changes
@@ -0,0 +1,469 @@
1
+ from tabsim.jax import coordinates as coord
2
+
3
+ import dask.array as da
4
+ from dask.delayed import delayed
5
+ from dask.array.core import Array
6
+ import xarray as xr
7
+
8
+
9
+ def radec_to_lmn(ra: Array, dec: Array, phase_centre: Array) -> Array:
10
+ n_src = ra.shape[0]
11
+
12
+ src_chunk = ra.chunksize[0]
13
+
14
+ input = xr.Dataset(
15
+ {
16
+ "ra": (["src"], ra),
17
+ "dec": (["src"], dec),
18
+ "phase_centre": (["cel_space"], phase_centre),
19
+ }
20
+ )
21
+ output = xr.Dataset(
22
+ {
23
+ "lmn": (
24
+ ["src", "lmn_space"],
25
+ da.zeros(
26
+ shape=(n_src, 3),
27
+ chunks=(src_chunk, 3),
28
+ dtype=float,
29
+ ),
30
+ )
31
+ }
32
+ )
33
+
34
+ def _radec_to_lmn(ds):
35
+ lmn = delayed(coord.radec_to_lmn, pure=True)(
36
+ ds.ra.data, ds.dec.data, ds.phase_centre.data
37
+ ).compute()
38
+ ds_out = xr.Dataset({"lmn": (["src", "lmn_space"], lmn)})
39
+ return ds_out
40
+
41
+ ds = xr.map_blocks(_radec_to_lmn, input, template=output)
42
+
43
+ return ds.lmn.data
44
+
45
+
46
+ radec_to_lmn.__doc__ = coord.radec_to_lmn.__doc__
47
+
48
+
49
+ def radec_to_XYZ(ra: Array, dec: Array) -> Array:
50
+ n_src = ra.shape[0]
51
+
52
+ src_chunk = ra.chunksize[0]
53
+
54
+ input = xr.Dataset(
55
+ {
56
+ "ra": (["src"], ra),
57
+ "dec": (["src"], dec),
58
+ }
59
+ )
60
+ output = xr.Dataset(
61
+ {
62
+ "XYZ": (
63
+ ["src", "space"],
64
+ da.zeros(
65
+ shape=(n_src, 3),
66
+ chunks=(src_chunk, 3),
67
+ dtype=float,
68
+ ),
69
+ )
70
+ }
71
+ )
72
+
73
+ def _radec_to_XYZ(ds):
74
+ XYZ = delayed(coord.radec_to_XYZ, pure=True)(ds.ra.data, ds.dec.data).compute()
75
+ ds_out = xr.Dataset({"XYZ": (["src", "space"], XYZ)})
76
+ return ds_out
77
+
78
+ ds = xr.map_blocks(_radec_to_XYZ, input, template=output)
79
+
80
+ return ds.XYZ.data
81
+
82
+
83
+ radec_to_XYZ.__doc__ = coord.radec_to_XYZ.__doc__
84
+
85
+
86
+ def ENU_to_GEO(geo_ref: Array, ENU: Array) -> Array:
87
+ n_ant = ENU.shape[0]
88
+
89
+ ant_chunk = ENU.chunksize[0]
90
+
91
+ input = xr.Dataset(
92
+ {
93
+ "geo_ref": (["geo_space"], geo_ref),
94
+ "ENU": (["ant", "space"], ENU),
95
+ }
96
+ )
97
+ output = xr.Dataset(
98
+ {
99
+ "GEO": (
100
+ ["bl", "space"],
101
+ da.zeros(
102
+ shape=(n_ant, 3),
103
+ chunks=(ant_chunk, 3),
104
+ dtype=float,
105
+ ),
106
+ )
107
+ }
108
+ )
109
+
110
+ def _ENU_to_GEO(ds):
111
+ GEO = delayed(coord.ENU_to_GEO, pure=True)(
112
+ ds.geo_ref.data, ds.ENU.data
113
+ ).compute()
114
+ ds_out = xr.Dataset({"GEO": (["ant", "space"], GEO)})
115
+ return ds_out
116
+
117
+ ds = xr.map_blocks(_ENU_to_GEO, input, template=output)
118
+
119
+ return ds.GEO.data
120
+
121
+
122
+ ENU_to_GEO.__doc__ = coord.ENU_to_GEO.__doc__
123
+
124
+
125
+ def GEO_to_XYZ(geo: Array, times: Array) -> Array:
126
+ n_time = geo.shape[0]
127
+
128
+ time_chunk = geo.chunksize[0]
129
+
130
+ input = xr.Dataset(
131
+ {
132
+ "geo": (["time", "space"], geo),
133
+ "times": (["time"], times),
134
+ }
135
+ )
136
+ output = xr.Dataset(
137
+ {
138
+ "XYZ": (
139
+ ["time", "space"],
140
+ da.zeros(
141
+ shape=(n_time, 3),
142
+ chunks=(time_chunk, 3),
143
+ dtype=float,
144
+ ),
145
+ )
146
+ }
147
+ )
148
+
149
+ def _GEO_to_XYZ(ds):
150
+ XYZ = delayed(coord.GEO_to_XYZ, pure=True)(ds.geo.data, ds.times.data).compute()
151
+ ds_out = xr.Dataset({"XYZ": (["time", "space"], XYZ)})
152
+ return ds_out
153
+
154
+ ds = xr.map_blocks(_GEO_to_XYZ, input, template=output)
155
+
156
+ return ds.XYZ.data
157
+
158
+
159
+ GEO_to_XYZ.__doc__ = coord.GEO_to_XYZ.__doc__
160
+
161
+
162
+ def GEO_to_XYZ_vmap0(geo: Array, times: Array) -> Array:
163
+ n_src, n_time = geo.shape[:2]
164
+
165
+ src_chunk = geo.chunks[0][0]
166
+ time_chunk = geo.chunks[1][0]
167
+
168
+ input = xr.Dataset(
169
+ {
170
+ "geo": (["src", "time", "space"], geo),
171
+ "times": (["time"], times),
172
+ }
173
+ )
174
+ output = xr.Dataset(
175
+ {
176
+ "XYZ": (
177
+ ["src", "time", "space"],
178
+ da.zeros(
179
+ shape=(n_src, n_time, 3),
180
+ chunks=(src_chunk, time_chunk, 3),
181
+ dtype=float,
182
+ ),
183
+ )
184
+ }
185
+ )
186
+
187
+ def _GEO_to_XYZ(ds):
188
+ XYZ = delayed(coord.GEO_to_XYZ_vmap0, pure=True)(
189
+ ds.geo.data, ds.times.data
190
+ ).compute()
191
+ ds_out = xr.Dataset({"XYZ": (["src", "time", "space"], XYZ)})
192
+ return ds_out
193
+
194
+ ds = xr.map_blocks(_GEO_to_XYZ, input, template=output)
195
+
196
+ return ds.XYZ.data
197
+
198
+
199
+ GEO_to_XYZ_vmap0.__doc__ = coord.GEO_to_XYZ_vmap0.__doc__
200
+
201
+
202
+ def GEO_to_XYZ_vmap1(geo: Array, times: Array) -> Array:
203
+ n_time, n_ant = geo.shape[:2]
204
+
205
+ time_chunk, ant_chunk = geo.chunksize[:2]
206
+
207
+ input = xr.Dataset(
208
+ {
209
+ "geo": (["time", "ant", "space"], geo),
210
+ "times": (["time"], times),
211
+ }
212
+ )
213
+ output = xr.Dataset(
214
+ {
215
+ "XYZ": (
216
+ ["time", "ant", "space"],
217
+ da.zeros(
218
+ shape=(n_time, n_ant, 3),
219
+ chunks=(time_chunk, ant_chunk, 3),
220
+ dtype=float,
221
+ ),
222
+ )
223
+ }
224
+ )
225
+
226
+ def _GEO_to_XYZ(ds):
227
+ XYZ = delayed(coord.GEO_to_XYZ_vmap1, pure=True)(
228
+ ds.geo.data, ds.times.data
229
+ ).compute()
230
+ ds_out = xr.Dataset({"XYZ": (["time", "ant", "space"], XYZ)})
231
+ return ds_out
232
+
233
+ ds = xr.map_blocks(_GEO_to_XYZ, input, template=output)
234
+
235
+ return ds.XYZ.data
236
+
237
+
238
+ GEO_to_XYZ_vmap1.__doc__ = coord.GEO_to_XYZ_vmap1.__doc__
239
+
240
+
241
+ def ITRF_to_XYZ(itrf: Array, gsa: Array) -> Array:
242
+ n_time = gsa.shape[0]
243
+ n_ant = itrf.shape[0]
244
+
245
+ time_chunk = gsa.chunksize[0]
246
+ ant_chunk = itrf.chunksize[0]
247
+
248
+ input = xr.Dataset(
249
+ {
250
+ "itrf": (["ant", "space"], itrf),
251
+ "gsa": (["time"], gsa),
252
+ }
253
+ )
254
+ output = xr.Dataset(
255
+ {
256
+ "xyz": (
257
+ ["time", "ant", "space"],
258
+ da.zeros(
259
+ shape=(n_time, n_ant, 3),
260
+ chunks=(time_chunk, ant_chunk, 3),
261
+ dtype=float,
262
+ ),
263
+ )
264
+ }
265
+ )
266
+
267
+ def _ITRF_to_XYZ(ds):
268
+ XYZ = delayed(coord.itrf_to_xyz, pure=True)(ds.itrf.data, ds.gsa.data).compute()
269
+ ds_out = xr.Dataset({"xyz": (["time", "ant", "space"], XYZ)})
270
+ return ds_out
271
+
272
+ ds = xr.map_blocks(_ITRF_to_XYZ, input, template=output)
273
+
274
+ return ds.xyz.data
275
+
276
+
277
+ ITRF_to_XYZ.__doc__ = coord.itrf_to_xyz.__doc__
278
+
279
+
280
+ def ENU_to_ITRF(ENU: Array, lat: Array, lon: Array, el: Array) -> Array:
281
+ n_ant = ENU.shape[0]
282
+
283
+ ant_chunk = ENU.chunksize[0]
284
+
285
+ input = xr.Dataset(
286
+ {
287
+ "ENU": (["ant", "space"], ENU),
288
+ "lat": lat,
289
+ "lon": lon,
290
+ "el": el,
291
+ }
292
+ )
293
+ output = xr.Dataset(
294
+ {
295
+ "ITRF": (
296
+ ["ant", "space"],
297
+ da.zeros(
298
+ shape=(n_ant, 3),
299
+ chunks=(ant_chunk, 3),
300
+ dtype=float,
301
+ ),
302
+ )
303
+ }
304
+ )
305
+
306
+ def _ENU_to_ITRF(ds):
307
+ ITRF = delayed(coord.enu_to_itrf, pure=True)(
308
+ ds.ENU.data,
309
+ ds.lat.data,
310
+ ds.lon.data,
311
+ ds.el.data,
312
+ ).compute()
313
+ ds_out = xr.Dataset({"ITRF": (["ant", "space"], ITRF)})
314
+ return ds_out
315
+
316
+ ds = xr.map_blocks(_ENU_to_ITRF, input, template=output)
317
+
318
+ return ds.ITRF.data
319
+
320
+
321
+ ENU_to_ITRF.__doc__ = coord.enu_to_itrf.__doc__
322
+
323
+
324
+ def ITRF_to_UVW(
325
+ itrf: Array,
326
+ h0: Array,
327
+ dec: Array,
328
+ ) -> Array:
329
+ n_ant = itrf.shape[0]
330
+ n_time = h0.shape[0]
331
+
332
+ ant_chunk = itrf.chunksize[0]
333
+ time_chunk = h0.chunksize[0]
334
+
335
+ input = xr.Dataset(
336
+ {
337
+ "itrf": (["ant", "space"], itrf),
338
+ "h0": (["time"], da.atleast_1d(h0)),
339
+ "dec": (["cel_space_1"], da.atleast_1d(dec)),
340
+ }
341
+ )
342
+
343
+ output = xr.Dataset(
344
+ {
345
+ "uvw": (
346
+ ["time", "ant", "space"],
347
+ da.zeros(
348
+ shape=(n_time, n_ant, 3),
349
+ chunks=(time_chunk, ant_chunk, 3),
350
+ dtype=float,
351
+ ),
352
+ )
353
+ }
354
+ )
355
+
356
+ def _ITRF_to_UVW(ds):
357
+ uvw = delayed(coord.itrf_to_uvw, pure=True)(
358
+ ds.itrf.data,
359
+ ds.h0.data,
360
+ ds.dec.data,
361
+ ).compute()
362
+ ds_out = xr.Dataset({"uvw": (["time", "ant", "space"], uvw)})
363
+ return ds_out
364
+
365
+ ds = xr.map_blocks(_ITRF_to_UVW, input, template=output)
366
+
367
+ return ds.uvw.data
368
+
369
+
370
+ ITRF_to_UVW.__doc__ = coord.itrf_to_uvw.__doc__
371
+
372
+
373
+ def angular_separation(rfi_xyz: Array, ants_xyz: Array, ra: Array, dec: Array) -> Array:
374
+ n_src, n_time = rfi_xyz.shape[:2]
375
+ n_ant = ants_xyz.shape[1]
376
+
377
+ src_chunk, time_chunk = rfi_xyz.chunksize[:2]
378
+ ant_chunk = ants_xyz.chunksize[1]
379
+
380
+ input = xr.Dataset(
381
+ {
382
+ "rfi_xyz": (["src", "time", "space"], rfi_xyz),
383
+ "ants_xyz": (["time", "ant", "space"], ants_xyz),
384
+ "ra": (["cel_space_0"], da.from_array([ra])),
385
+ "dec": (["cel_space_1"], da.from_array([dec])),
386
+ }
387
+ )
388
+
389
+ output = xr.Dataset(
390
+ {
391
+ "sep": (
392
+ ["src", "time", "ant"],
393
+ da.zeros(
394
+ shape=(n_src, n_time, n_ant),
395
+ chunks=(src_chunk, time_chunk, ant_chunk),
396
+ dtype=float,
397
+ ),
398
+ )
399
+ }
400
+ )
401
+
402
+ def _angular_separation(ds):
403
+ sep = delayed(coord.angular_separation, pure=True)(
404
+ ds.rfi_xyz.data, ds.ants_xyz.data, ds.ra.data, ds.dec.data
405
+ ).compute()
406
+ ds_out = xr.Dataset({"sep": (["src", "time", "ant"], sep)})
407
+ return ds_out
408
+
409
+ ds = xr.map_blocks(_angular_separation, input, template=output)
410
+
411
+ return ds.sep.data
412
+
413
+
414
+ angular_separation.__doc__ = coord.angular_separation.__doc__
415
+
416
+
417
+ def orbit_vmap(
418
+ times: Array,
419
+ elevation: Array,
420
+ inclination: Array,
421
+ lon_asc_node: Array,
422
+ periapsis,
423
+ ) -> Array:
424
+ n_time = times.shape[0]
425
+ n_src = elevation.shape[0]
426
+
427
+ time_chunk = times.chunksize[0]
428
+ src_chunk = elevation.chunksize[0]
429
+
430
+ input = xr.Dataset(
431
+ {
432
+ "times": (["time"], times),
433
+ "elevation": (["src"], elevation),
434
+ "inclination": (["src"], inclination),
435
+ "lon_asc_node": (["src"], lon_asc_node),
436
+ "periapsis": (["src"], periapsis),
437
+ }
438
+ )
439
+
440
+ output = xr.Dataset(
441
+ {
442
+ "orbit": (
443
+ ["src", "time", "space"],
444
+ da.zeros(
445
+ shape=(n_src, n_time, 3),
446
+ chunks=(src_chunk, time_chunk, 3),
447
+ dtype=float,
448
+ ),
449
+ )
450
+ }
451
+ )
452
+
453
+ def _orbit_vmap(ds):
454
+ orbit = delayed(coord.orbit_vmap, pure=True)(
455
+ ds.times.data,
456
+ ds.elevation.data,
457
+ ds.inclination.data,
458
+ ds.lon_asc_node.data,
459
+ ds.periapsis.data,
460
+ ).compute()
461
+ ds_out = xr.Dataset({"orbit": (["src", "time", "space"], orbit)})
462
+ return ds_out
463
+
464
+ ds = xr.map_blocks(_orbit_vmap, input, template=output)
465
+
466
+ return ds.orbit.data
467
+
468
+
469
+ orbit_vmap.__doc__ = coord.orbit_vmap.__doc__
tabsim/dask/extras.py ADDED
@@ -0,0 +1,60 @@
1
+ import jax.numpy as jnp
2
+
3
+ def get_factors(n: int):
4
+ """Get the integer factors of n.
5
+
6
+ Parameters:
7
+ -----------
8
+ n: int
9
+ Number to get the factors of.
10
+
11
+ Returns:
12
+ --------
13
+ factors: array_like
14
+ The factors of n.
15
+ """
16
+ factors = [1, n]
17
+ root_n = jnp.sqrt(n)
18
+ if root_n == int(root_n):
19
+ factors.append(root_n)
20
+ for i in range(1, int(root_n)):
21
+ if n % i == 0:
22
+ factors += [i, n // i]
23
+ return jnp.unique(jnp.array(factors).sort().astype(int))
24
+
25
+
26
+ def get_chunksizes(n_t: int, n_f: int, n_int: int, n_bl: int, MB_max: float):
27
+ """Get the chunk sizes for a given number of time and frequency samples.
28
+
29
+ Parameters:
30
+ -----------
31
+ n_t: int
32
+ Number of time samples.
33
+ n_f: int
34
+ Number of frequency samples.
35
+ n_int: int
36
+ Number of integration samples per time sample.
37
+ n_bl: int
38
+ Number of baselines.
39
+ MB_max: float
40
+ Maximum megabytes to use for a chunk.
41
+
42
+ Returns:
43
+ --------
44
+ chunksize: dict
45
+ Dictionary containing the time and frequency chunk sizes.
46
+ """
47
+ time_factors = get_factors(n_t)
48
+ freq_factors = get_factors(n_f)
49
+ extra = MB_max * 1e6 / (16 * n_int * n_bl)
50
+ tt, ff = jnp.meshgrid(time_factors, freq_factors)
51
+ idx = jnp.argmin(jnp.abs(tt * ff - extra))
52
+ time_chunksize = int(tt.flatten()[idx])
53
+ freq_chunksize = int(ff.flatten()[idx])
54
+ chunk_bytes = 16 * n_int * n_bl * time_chunksize * freq_chunksize
55
+ chunksize = {
56
+ "time": time_chunksize,
57
+ "freq": freq_chunksize,
58
+ "chunk_bytes": f"{chunk_bytes/1e6:.0f} MB",
59
+ }
60
+ return chunksize