xradio 0.0.40__py3-none-any.whl → 0.0.41__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.
- xradio/{vis → correlated_data}/__init__.py +3 -2
- xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/_tables/load_main_table.py +1 -1
- xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/_tables/read.py +14 -0
- xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/conversion.py +117 -58
- xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/create_antenna_xds.py +195 -167
- xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/create_field_and_source_xds.py +40 -39
- xradio/correlated_data/_utils/_ms/msv4_info_dicts.py +203 -0
- xradio/correlated_data/_utils/_ms/msv4_sub_xdss.py +516 -0
- xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/subtables.py +1 -1
- xradio/{vis/_vis_utils → correlated_data/_utils}/zarr.py +3 -3
- xradio/{vis → correlated_data}/convert_msv2_to_processing_set.py +9 -2
- xradio/correlated_data/correlated_xds.py +13 -0
- xradio/{vis → correlated_data}/load_processing_set.py +13 -17
- xradio/{vis/read_processing_set.py → correlated_data/open_processing_set.py} +20 -22
- xradio/{vis/_processing_set.py → correlated_data/processing_set.py} +11 -12
- xradio/{vis → correlated_data}/schema.py +572 -186
- xradio/correlated_data/test__processing_set.py +74 -0
- {xradio-0.0.40.dist-info → xradio-0.0.41.dist-info}/METADATA +9 -10
- xradio-0.0.41.dist-info/RECORD +75 -0
- {xradio-0.0.40.dist-info → xradio-0.0.41.dist-info}/WHEEL +1 -1
- xradio/vis/_vis_utils/_ms/msv4_infos.py +0 -0
- xradio/vis/_vis_utils/_ms/msv4_sub_xdss.py +0 -306
- xradio-0.0.40.dist-info/RECORD +0 -73
- /xradio/{vis/_vis_utils → correlated_data/_utils}/__init__.py +0 -0
- /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/_tables/load.py +0 -0
- /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/_tables/read_main_table.py +0 -0
- /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/_tables/read_subtables.py +0 -0
- /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/_tables/table_query.py +0 -0
- /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/_tables/write.py +0 -0
- /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/_tables/write_exp_api.py +0 -0
- /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/chunks.py +0 -0
- /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/descr.py +0 -0
- /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/msv2_msv3.py +0 -0
- /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/msv2_to_msv4_meta.py +0 -0
- /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/optimised_functions.py +0 -0
- /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/partition_queries.py +0 -0
- /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/partitions.py +0 -0
- /xradio/{vis/_vis_utils → correlated_data/_utils}/_utils/cds.py +0 -0
- /xradio/{vis/_vis_utils → correlated_data/_utils}/_utils/partition_attrs.py +0 -0
- /xradio/{vis/_vis_utils → correlated_data/_utils}/_utils/stokes_types.py +0 -0
- /xradio/{vis/_vis_utils → correlated_data/_utils}/_utils/xds_helper.py +0 -0
- /xradio/{vis/_vis_utils → correlated_data/_utils}/_zarr/encoding.py +0 -0
- /xradio/{vis/_vis_utils → correlated_data/_utils}/_zarr/read.py +0 -0
- /xradio/{vis/_vis_utils → correlated_data/_utils}/_zarr/write.py +0 -0
- /xradio/{vis/_vis_utils → correlated_data/_utils}/ms.py +0 -0
- {xradio-0.0.40.dist-info → xradio-0.0.41.dist-info}/LICENSE.txt +0 -0
- {xradio-0.0.40.dist-info → xradio-0.0.41.dist-info}/top_level.txt +0 -0
|
@@ -6,14 +6,16 @@ import numpy as np
|
|
|
6
6
|
import xarray as xr
|
|
7
7
|
import os
|
|
8
8
|
|
|
9
|
-
from xradio.
|
|
10
|
-
from xradio.
|
|
9
|
+
from xradio.correlated_data._utils._ms.subtables import subt_rename_ids
|
|
10
|
+
from xradio.correlated_data._utils._ms._tables.read import (
|
|
11
11
|
load_generic_table,
|
|
12
|
+
convert_casacore_time,
|
|
12
13
|
convert_casacore_time_to_mjd,
|
|
13
14
|
make_taql_where_between_min_max,
|
|
15
|
+
table_exists,
|
|
14
16
|
)
|
|
15
17
|
from xradio._utils.schema import convert_generic_xds_to_xradio_schema
|
|
16
|
-
from xradio.
|
|
18
|
+
from xradio.correlated_data._utils._ms.msv4_sub_xdss import interpolate_to_time
|
|
17
19
|
|
|
18
20
|
from xradio._utils.list_and_array import (
|
|
19
21
|
check_if_consistent,
|
|
@@ -29,8 +31,6 @@ def create_antenna_xds(
|
|
|
29
31
|
antenna_id: list,
|
|
30
32
|
feed_id: list,
|
|
31
33
|
telescope_name: str,
|
|
32
|
-
time_min_max: Tuple[np.float64, np.float64],
|
|
33
|
-
phase_cal_interp_time: Union[xr.DataArray, None] = None,
|
|
34
34
|
) -> xr.Dataset:
|
|
35
35
|
"""
|
|
36
36
|
Create an Xarray Dataset containing antenna information.
|
|
@@ -47,10 +47,6 @@ def create_antenna_xds(
|
|
|
47
47
|
List of feed IDs.
|
|
48
48
|
telescope_name : str
|
|
49
49
|
Name of the telescope.
|
|
50
|
-
time_min_max : Tuple[np.float46, np.float64]
|
|
51
|
-
Min / max times to constrain loading (usually to the time range relevant to an MSv4)
|
|
52
|
-
phase_cal_interp_time : Union[xr.DataArray, None]
|
|
53
|
-
Time axis to interpolate the data vars to (usually main MSv4 time)
|
|
54
50
|
|
|
55
51
|
Returns
|
|
56
52
|
----------
|
|
@@ -64,13 +60,6 @@ def create_antenna_xds(
|
|
|
64
60
|
ant_xds, in_file, antenna_id, feed_id, spectral_window_id
|
|
65
61
|
)
|
|
66
62
|
|
|
67
|
-
ant_xds = extract_phase_cal_info(
|
|
68
|
-
ant_xds, in_file, spectral_window_id, time_min_max, phase_cal_interp_time
|
|
69
|
-
) # Only used in VLBI.
|
|
70
|
-
ant_xds = extract_gain_curve_info(
|
|
71
|
-
ant_xds, in_file, spectral_window_id
|
|
72
|
-
) # Only used in VLBI.
|
|
73
|
-
|
|
74
63
|
ant_xds.attrs["overall_telescope_name"] = telescope_name
|
|
75
64
|
return ant_xds
|
|
76
65
|
|
|
@@ -164,6 +153,15 @@ def extract_antenna_info(
|
|
|
164
153
|
else:
|
|
165
154
|
ant_xds.attrs["relocatable_antennas"] = False
|
|
166
155
|
|
|
156
|
+
ant_xds = ant_xds.assign_coords(
|
|
157
|
+
{
|
|
158
|
+
"telescope_name": (
|
|
159
|
+
"antenna_name",
|
|
160
|
+
np.array([telescope_name for ant in ant_xds["antenna_name"]]),
|
|
161
|
+
)
|
|
162
|
+
}
|
|
163
|
+
)
|
|
164
|
+
|
|
167
165
|
return ant_xds
|
|
168
166
|
|
|
169
167
|
|
|
@@ -277,103 +275,122 @@ def extract_feed_info(
|
|
|
277
275
|
return ant_xds
|
|
278
276
|
|
|
279
277
|
|
|
280
|
-
def
|
|
281
|
-
|
|
278
|
+
def create_gain_curve_xds(
|
|
279
|
+
in_file: str, spectral_window_id: int, ant_xds: xr.Dataset
|
|
282
280
|
) -> xr.Dataset:
|
|
283
281
|
"""
|
|
284
|
-
|
|
282
|
+
Produces a gain_curve_xds, reformats MSv2 GAIN CURVE table content to MSv4 schema.
|
|
285
283
|
|
|
286
284
|
Parameters
|
|
287
285
|
----------
|
|
288
|
-
ant_xds : xr.Dataset
|
|
289
|
-
The dataset that will be updated with gain curve information.
|
|
290
286
|
in_file : str
|
|
291
287
|
Path to the input MSv2.
|
|
292
288
|
spectral_window_id : int
|
|
293
289
|
The ID of the spectral window.
|
|
290
|
+
ant_xds : xr.Dataset
|
|
291
|
+
The antenna_xds that has information such as names, stations, etc., for coordinates
|
|
294
292
|
|
|
295
293
|
Returns
|
|
296
294
|
-------
|
|
297
295
|
xr.Dataset
|
|
298
296
|
The updated antenna dataset with gain curve information.
|
|
299
297
|
"""
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
298
|
+
|
|
299
|
+
gain_curve_xds = None
|
|
300
|
+
if not table_exists(os.path.join(in_file, "GAIN_CURVE")):
|
|
301
|
+
return gain_curve_xds
|
|
302
|
+
|
|
303
|
+
generic_gain_curve_xds = load_generic_table(
|
|
304
|
+
in_file,
|
|
305
|
+
"GAIN_CURVE",
|
|
306
|
+
taql_where=f" where (ANTENNA_ID IN [{','.join(map(str,ant_xds.antenna_id.values))}]) AND (SPECTRAL_WINDOW_ID = {spectral_window_id})",
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
if not generic_gain_curve_xds.data_vars:
|
|
310
|
+
# Some times the gain_curve table is empty (this is the case with ngEHT simulation data we have).
|
|
311
|
+
return gain_curve_xds
|
|
312
|
+
|
|
313
|
+
assert (
|
|
314
|
+
len(generic_gain_curve_xds.SPECTRAL_WINDOW_ID) == 1
|
|
315
|
+
), "Only one spectral window is supported."
|
|
316
|
+
generic_gain_curve_xds = generic_gain_curve_xds.isel(
|
|
317
|
+
SPECTRAL_WINDOW_ID=0, drop=True
|
|
318
|
+
) # Drop the spectral window dimension as it is singleton.
|
|
319
|
+
|
|
320
|
+
assert (
|
|
321
|
+
len(generic_gain_curve_xds.TIME) == 1
|
|
322
|
+
), "Only one gain curve measurement per antenna is supported."
|
|
323
|
+
measured_time = generic_gain_curve_xds.coords["TIME"].values[0]
|
|
324
|
+
generic_gain_curve_xds = generic_gain_curve_xds.isel(TIME=0, drop=True)
|
|
325
|
+
|
|
326
|
+
generic_gain_curve_xds = generic_gain_curve_xds.sel(
|
|
327
|
+
ANTENNA_ID=ant_xds.antenna_id, drop=False
|
|
328
|
+
) # Make sure the antenna_id is in the same order as the xds .
|
|
329
|
+
|
|
330
|
+
gain_curve_xds = xr.Dataset(attrs={"type": "gain_curve"})
|
|
331
|
+
|
|
332
|
+
to_new_data_variables = {
|
|
333
|
+
"INTERVAL": ["GAIN_CURVE_INTERVAL", ["antenna_name"]],
|
|
334
|
+
"GAIN": [
|
|
305
335
|
"GAIN_CURVE",
|
|
306
|
-
|
|
307
|
-
|
|
336
|
+
["antenna_name", "poly_term", "receptor_label"],
|
|
337
|
+
],
|
|
338
|
+
"SENSITIVITY": [
|
|
339
|
+
"GAIN_CURVE_SENSITIVITY",
|
|
340
|
+
["antenna_name", "receptor_label"],
|
|
341
|
+
],
|
|
342
|
+
}
|
|
308
343
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
assert (
|
|
314
|
-
len(generic_gain_curve_xds.SPECTRAL_WINDOW_ID) == 1
|
|
315
|
-
), "Only one spectral window is supported."
|
|
316
|
-
generic_gain_curve_xds = generic_gain_curve_xds.isel(
|
|
317
|
-
SPECTRAL_WINDOW_ID=0, drop=True
|
|
318
|
-
) # Drop the spectral window dimension as it is singleton.
|
|
319
|
-
|
|
320
|
-
assert (
|
|
321
|
-
len(generic_gain_curve_xds.TIME) == 1
|
|
322
|
-
), "Only one gain curve measurement per antenna is supported."
|
|
323
|
-
generic_gain_curve_xds = generic_gain_curve_xds.isel(TIME=0, drop=True)
|
|
324
|
-
|
|
325
|
-
generic_gain_curve_xds = generic_gain_curve_xds.sel(
|
|
326
|
-
ANTENNA_ID=ant_xds.antenna_id, drop=False
|
|
327
|
-
) # Make sure the antenna_id is in the same order as the xds .
|
|
328
|
-
|
|
329
|
-
to_new_data_variables = {
|
|
330
|
-
"INTERVAL": ["GAIN_CURVE_INTERVAL", ["antenna_name"]],
|
|
331
|
-
"GAIN": [
|
|
332
|
-
"GAIN_CURVE",
|
|
333
|
-
["antenna_name", "poly_term", "receptor_label"],
|
|
334
|
-
],
|
|
335
|
-
"SENSITIVITY": [
|
|
336
|
-
"GAIN_CURVE_SENSITIVITY",
|
|
337
|
-
["antenna_name", "receptor_label"],
|
|
338
|
-
],
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
to_new_coords = {
|
|
342
|
-
"TYPE": ["gain_curve_type", ["antenna_name"]],
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
# print(generic_gain_curve_xds)
|
|
346
|
-
|
|
347
|
-
ant_xds = convert_generic_xds_to_xradio_schema(
|
|
348
|
-
generic_gain_curve_xds,
|
|
349
|
-
ant_xds,
|
|
350
|
-
to_new_data_variables,
|
|
351
|
-
to_new_coords,
|
|
352
|
-
)
|
|
353
|
-
ant_xds["GAIN_CURVE"] = ant_xds["GAIN_CURVE"].transpose(
|
|
354
|
-
"antenna_name", "receptor_label", "poly_term"
|
|
355
|
-
)
|
|
344
|
+
to_new_coords = {
|
|
345
|
+
"TYPE": ["gain_curve_type", ["antenna_name"]],
|
|
346
|
+
}
|
|
356
347
|
|
|
357
|
-
|
|
348
|
+
gain_curve_xds = convert_generic_xds_to_xradio_schema(
|
|
349
|
+
generic_gain_curve_xds,
|
|
350
|
+
gain_curve_xds,
|
|
351
|
+
to_new_data_variables,
|
|
352
|
+
to_new_coords,
|
|
353
|
+
)
|
|
358
354
|
|
|
359
|
-
|
|
360
|
-
|
|
355
|
+
ant_borrowed_coords = {
|
|
356
|
+
"antenna_name": ant_xds.coords["antenna_name"],
|
|
357
|
+
"station": ant_xds.coords["station"],
|
|
358
|
+
"mount": ant_xds.coords["mount"],
|
|
359
|
+
"telescope_name": ant_xds.coords["telescope_name"],
|
|
360
|
+
"receptor_label": ant_xds.coords["receptor_label"],
|
|
361
|
+
"polarization_type": ant_xds.coords["polarization_type"],
|
|
362
|
+
}
|
|
363
|
+
gain_curve_xds = gain_curve_xds.assign_coords(ant_borrowed_coords)
|
|
364
|
+
|
|
365
|
+
gain_curve_xds.attrs.update(
|
|
366
|
+
{
|
|
367
|
+
"measured_date": np.datetime_as_string(
|
|
368
|
+
convert_casacore_time([measured_time])[0]
|
|
369
|
+
)
|
|
370
|
+
}
|
|
371
|
+
)
|
|
361
372
|
|
|
373
|
+
return gain_curve_xds
|
|
362
374
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
375
|
+
|
|
376
|
+
def create_phase_calibration_xds(
|
|
377
|
+
in_file: str,
|
|
378
|
+
spectral_window_id: int,
|
|
379
|
+
ant_xds: xr.Dataset,
|
|
380
|
+
time_min_max: Tuple[np.float64, np.float64],
|
|
381
|
+
phase_cal_interp_time: Union[xr.DataArray, None] = None,
|
|
382
|
+
) -> xr.Dataset:
|
|
366
383
|
"""
|
|
367
|
-
|
|
384
|
+
Produces a phase_calibration_xds, reformats MSv2 Phase Cal table content to MSv4 schema.
|
|
368
385
|
|
|
369
386
|
Parameters
|
|
370
387
|
----------
|
|
371
|
-
ant_xds : xr.Dataset
|
|
372
|
-
The dataset that will be updated with phase cal information.
|
|
373
388
|
in_file : str
|
|
374
389
|
Path to the input MSv2.
|
|
375
390
|
spectral_window_id : int
|
|
376
391
|
The ID of the spectral window.
|
|
392
|
+
ant_xds : xr.Dataset
|
|
393
|
+
The antenna_xds that has information such as names, stations, etc., for coordinates
|
|
377
394
|
time_min_max : Tuple[np.float46, np.float64]
|
|
378
395
|
Min / max times to constrain loading (usually to the time range relevant to an MSv4)
|
|
379
396
|
interp_time : Union[xr.DataArray, None]
|
|
@@ -385,98 +402,109 @@ def extract_phase_cal_info(
|
|
|
385
402
|
The updated antenna dataset with phase cal information.
|
|
386
403
|
"""
|
|
387
404
|
|
|
388
|
-
|
|
405
|
+
phase_cal_xds = None
|
|
406
|
+
if not table_exists(os.path.join(in_file, "PHASE_CAL")):
|
|
407
|
+
return phase_cal_xds
|
|
389
408
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
409
|
+
# Only read data between the min and max times of the visibility data in the MSv4.
|
|
410
|
+
taql_time_range = make_taql_where_between_min_max(
|
|
411
|
+
time_min_max, in_file, "PHASE_CAL", "TIME"
|
|
412
|
+
)
|
|
413
|
+
generic_phase_cal_xds = load_generic_table(
|
|
414
|
+
in_file,
|
|
415
|
+
"PHASE_CAL",
|
|
416
|
+
timecols=["TIME"],
|
|
417
|
+
taql_where=f" {taql_time_range} AND (ANTENNA_ID IN [{','.join(map(str,ant_xds.antenna_id.values))}]) AND (SPECTRAL_WINDOW_ID = {spectral_window_id})",
|
|
418
|
+
)
|
|
400
419
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
to_new_data_variables = {
|
|
413
|
-
"INTERVAL": ["PHASE_CAL_INTERVAL", ["antenna_name", "time_phase_cal"]],
|
|
414
|
-
"TONE_FREQUENCY": [
|
|
415
|
-
"PHASE_CAL_TONE_FREQUENCY",
|
|
416
|
-
["antenna_name", "time_phase_cal", "tone_label", "receptor_label"],
|
|
417
|
-
],
|
|
418
|
-
"PHASE_CAL": [
|
|
419
|
-
"PHASE_CAL",
|
|
420
|
-
["antenna_name", "time_phase_cal", "tone_label", "receptor_label"],
|
|
421
|
-
],
|
|
422
|
-
"CABLE_CAL": ["PHASE_CAL_CABLE_CAL", ["antenna_name", "time_phase_cal"]],
|
|
423
|
-
}
|
|
420
|
+
assert (
|
|
421
|
+
len(generic_phase_cal_xds.SPECTRAL_WINDOW_ID) == 1
|
|
422
|
+
), "Only one spectral window is supported."
|
|
423
|
+
generic_phase_cal_xds = generic_phase_cal_xds.isel(
|
|
424
|
+
SPECTRAL_WINDOW_ID=0, drop=True
|
|
425
|
+
) # Drop the spectral window dimension as it is singleton.
|
|
426
|
+
|
|
427
|
+
generic_phase_cal_xds = generic_phase_cal_xds.sel(
|
|
428
|
+
ANTENNA_ID=ant_xds.antenna_id, drop=False
|
|
429
|
+
) # Make sure the antenna_id is in the same order as the xds.
|
|
424
430
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
431
|
+
to_new_data_variables = {
|
|
432
|
+
"INTERVAL": ["PHASE_CAL_INTERVAL", ["antenna_name", "time_phase_cal"]],
|
|
433
|
+
"TONE_FREQUENCY": [
|
|
434
|
+
"PHASE_CAL_TONE_FREQUENCY",
|
|
435
|
+
["antenna_name", "time_phase_cal", "tone_label", "receptor_label"],
|
|
436
|
+
],
|
|
437
|
+
"PHASE_CAL": [
|
|
438
|
+
"PHASE_CAL",
|
|
439
|
+
["antenna_name", "time_phase_cal", "tone_label", "receptor_label"],
|
|
440
|
+
],
|
|
441
|
+
"CABLE_CAL": ["PHASE_CAL_CABLE_CAL", ["antenna_name", "time_phase_cal"]],
|
|
442
|
+
}
|
|
428
443
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
ant_xds["PHASE_CAL"] = ant_xds["PHASE_CAL"].transpose(
|
|
433
|
-
"antenna_name", "time_phase_cal", "receptor_label", "tone_label"
|
|
434
|
-
)
|
|
444
|
+
to_new_coords = {
|
|
445
|
+
"TIME": ["time_phase_cal", ["time_phase_cal"]],
|
|
446
|
+
}
|
|
435
447
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
# ant_xds = ant_xds.assign_coords({"tone_label" : "freq_" + np.arange(ant_xds.sizes["tone_label"]).astype(str)}) #Works on laptop but fails in github test runner.
|
|
441
|
-
ant_xds = ant_xds.assign_coords(
|
|
442
|
-
{
|
|
443
|
-
"tone_label": np.array(
|
|
444
|
-
list(
|
|
445
|
-
map(
|
|
446
|
-
lambda x, y: x + "_" + y,
|
|
447
|
-
["freq"] * ant_xds.sizes["tone_label"],
|
|
448
|
-
np.arange(ant_xds.sizes["tone_label"]).astype(str),
|
|
449
|
-
)
|
|
450
|
-
)
|
|
451
|
-
)
|
|
452
|
-
}
|
|
453
|
-
)
|
|
448
|
+
phase_cal_xds = xr.Dataset(attrs={"type": "phase_cal"})
|
|
449
|
+
phase_cal_xds = convert_generic_xds_to_xradio_schema(
|
|
450
|
+
generic_phase_cal_xds, phase_cal_xds, to_new_data_variables, to_new_coords
|
|
451
|
+
)
|
|
454
452
|
|
|
455
|
-
|
|
456
|
-
|
|
453
|
+
phase_cal_xds["PHASE_CAL"] = phase_cal_xds["PHASE_CAL"].transpose(
|
|
454
|
+
"antenna_name", "time_phase_cal", "receptor_label", "tone_label"
|
|
455
|
+
)
|
|
456
|
+
phase_cal_xds["PHASE_CAL_TONE_FREQUENCY"] = phase_cal_xds[
|
|
457
|
+
"PHASE_CAL_TONE_FREQUENCY"
|
|
458
|
+
].transpose("antenna_name", "time_phase_cal", "receptor_label", "tone_label")
|
|
459
|
+
|
|
460
|
+
ant_borrowed_coords = {
|
|
461
|
+
"antenna_name": ant_xds.coords["antenna_name"],
|
|
462
|
+
"station": ant_xds.coords["station"],
|
|
463
|
+
"mount": ant_xds.coords["mount"],
|
|
464
|
+
"telescope_name": ant_xds.coords["telescope_name"],
|
|
465
|
+
"receptor_label": ant_xds.coords["receptor_label"],
|
|
466
|
+
"polarization_type": ant_xds.coords["polarization_type"],
|
|
467
|
+
}
|
|
468
|
+
# phase_cal_xds = phase_cal_xds.assign_coords({"tone_label" : "freq_" + np.arange(phase_cal_xds.sizes["tone_label"]).astype(str)}) #Works on laptop but fails in github test runner.
|
|
469
|
+
tone_label_coord = {
|
|
470
|
+
"tone_label": np.array(
|
|
471
|
+
list(
|
|
472
|
+
map(
|
|
473
|
+
lambda x, y: x + "_" + y,
|
|
474
|
+
["freq"] * phase_cal_xds.sizes["tone_label"],
|
|
475
|
+
np.arange(phase_cal_xds.sizes["tone_label"]).astype(str),
|
|
476
|
+
)
|
|
477
|
+
)
|
|
457
478
|
)
|
|
479
|
+
}
|
|
480
|
+
phase_cal_xds = phase_cal_xds.assign_coords(ant_borrowed_coords | tone_label_coord)
|
|
458
481
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
)
|
|
482
|
+
# Adjust expected types
|
|
483
|
+
phase_cal_xds["time_phase_cal"] = (
|
|
484
|
+
phase_cal_xds.time_phase_cal.astype("float64").astype("float64") / 10**9
|
|
485
|
+
)
|
|
462
486
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
487
|
+
phase_cal_xds = interpolate_to_time(
|
|
488
|
+
phase_cal_xds,
|
|
489
|
+
phase_cal_interp_time,
|
|
490
|
+
"antenna_xds",
|
|
491
|
+
time_name="time_phase_cal",
|
|
492
|
+
)
|
|
469
493
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
"time_phase_cal"
|
|
477
|
-
)
|
|
494
|
+
time_coord_attrs = {
|
|
495
|
+
"type": "time",
|
|
496
|
+
"units": ["s"],
|
|
497
|
+
"scale": "UTC",
|
|
498
|
+
"format": "UNIX",
|
|
499
|
+
}
|
|
478
500
|
|
|
479
|
-
|
|
501
|
+
# If we interpolate rename the time_phase_cal axis to time.
|
|
502
|
+
if phase_cal_interp_time is not None:
|
|
503
|
+
time_coord = {"time": ("time_phase_cal", phase_cal_interp_time.data)}
|
|
504
|
+
phase_cal_xds = phase_cal_xds.assign_coords(time_coord)
|
|
505
|
+
phase_cal_xds.coords["time"].attrs.update(time_coord_attrs)
|
|
506
|
+
phase_cal_xds = phase_cal_xds.swap_dims({"time_phase_cal": "time"}).drop_vars(
|
|
507
|
+
"time_phase_cal"
|
|
508
|
+
)
|
|
480
509
|
|
|
481
|
-
|
|
482
|
-
return ant_xds
|
|
510
|
+
return phase_cal_xds
|
|
@@ -6,9 +6,9 @@ import numpy as np
|
|
|
6
6
|
import xarray as xr
|
|
7
7
|
|
|
8
8
|
import toolviper.utils.logger as logger
|
|
9
|
-
from xradio.
|
|
10
|
-
from xradio.
|
|
11
|
-
from xradio.
|
|
9
|
+
from xradio.correlated_data._utils._ms.msv4_sub_xdss import interpolate_to_time
|
|
10
|
+
from xradio.correlated_data._utils._ms.subtables import subt_rename_ids
|
|
11
|
+
from xradio.correlated_data._utils._ms._tables.read import (
|
|
12
12
|
convert_casacore_time_to_mjd,
|
|
13
13
|
make_taql_where_between_min_max,
|
|
14
14
|
load_generic_table,
|
|
@@ -160,7 +160,7 @@ def extract_ephemeris_info(
|
|
|
160
160
|
|
|
161
161
|
# Get meta data.
|
|
162
162
|
ephemeris_meta = ephemeris_xds.attrs["other"]["msv2"]["ctds_attrs"]
|
|
163
|
-
|
|
163
|
+
ephemeris_column_description = ephemeris_xds.attrs["other"]["msv2"]["ctds_attrs"][
|
|
164
164
|
"column_descriptions"
|
|
165
165
|
]
|
|
166
166
|
|
|
@@ -174,27 +174,27 @@ def extract_ephemeris_info(
|
|
|
174
174
|
sky_coord_frame = "ICRS" # We will have to just assume this.
|
|
175
175
|
|
|
176
176
|
# Find out witch keyword is used for units (UNIT/QuantumUnits)
|
|
177
|
-
if "UNIT" in
|
|
177
|
+
if "UNIT" in ephemeris_column_description["RA"]["keywords"]:
|
|
178
178
|
unit_keyword = "UNIT"
|
|
179
179
|
else:
|
|
180
180
|
unit_keyword = "QuantumUnits"
|
|
181
181
|
|
|
182
182
|
temp_xds = xr.Dataset()
|
|
183
183
|
|
|
184
|
-
# Add mandatory data:
|
|
185
|
-
|
|
184
|
+
# Add mandatory data: OBSERVER_POSITION
|
|
185
|
+
observer_position = [
|
|
186
186
|
ephemeris_meta["GeoLong"],
|
|
187
187
|
ephemeris_meta["GeoLat"],
|
|
188
188
|
ephemeris_meta["GeoDist"],
|
|
189
189
|
]
|
|
190
|
-
temp_xds["
|
|
191
|
-
|
|
190
|
+
temp_xds["OBSERVER_POSITION"] = xr.DataArray(
|
|
191
|
+
observer_position, dims=["ellipsoid_pos_label"]
|
|
192
192
|
)
|
|
193
|
-
temp_xds["
|
|
193
|
+
temp_xds["OBSERVER_POSITION"].attrs.update(
|
|
194
194
|
{
|
|
195
195
|
"type": "location",
|
|
196
196
|
"units": ["deg", "deg", "m"],
|
|
197
|
-
"data":
|
|
197
|
+
"data": observer_position,
|
|
198
198
|
"ellipsoid": "WGS84",
|
|
199
199
|
"origin_object_name": "Earth",
|
|
200
200
|
"coordinate_system": ephemeris_meta["obsloc"].lower(),
|
|
@@ -210,13 +210,13 @@ def extract_ephemeris_info(
|
|
|
210
210
|
ephemeris_xds["Rho"].data,
|
|
211
211
|
)
|
|
212
212
|
),
|
|
213
|
-
dims=["
|
|
213
|
+
dims=["time_ephemeris", "sky_pos_label"],
|
|
214
214
|
)
|
|
215
215
|
# Have to use cast_to_str because the ephemeris table units are not consistently in a list or a string.
|
|
216
216
|
sky_coord_units = [
|
|
217
|
-
cast_to_str(
|
|
218
|
-
cast_to_str(
|
|
219
|
-
cast_to_str(
|
|
217
|
+
cast_to_str(ephemeris_column_description["RA"]["keywords"][unit_keyword]),
|
|
218
|
+
cast_to_str(ephemeris_column_description["DEC"]["keywords"][unit_keyword]),
|
|
219
|
+
cast_to_str(ephemeris_column_description["Rho"]["keywords"][unit_keyword]),
|
|
220
220
|
]
|
|
221
221
|
temp_xds["SOURCE_LOCATION"].attrs.update(
|
|
222
222
|
{"type": "sky_coord", "frame": sky_coord_frame, "units": sky_coord_units}
|
|
@@ -227,16 +227,17 @@ def extract_ephemeris_info(
|
|
|
227
227
|
# Metadata has to be fixed manually. Alternatively, issues like
|
|
228
228
|
# UNIT/QuantumUnits issue could be handled in convert_generic_xds_to_xradio_schema,
|
|
229
229
|
# but for now preferring not to pollute that function.
|
|
230
|
+
time_ephemeris_dim = ["time_ephemeris"]
|
|
230
231
|
to_new_data_variables = {
|
|
231
232
|
# mandatory: SOURCE_RADIAL_VELOCITY
|
|
232
|
-
"RadVel": ["SOURCE_RADIAL_VELOCITY",
|
|
233
|
+
"RadVel": ["SOURCE_RADIAL_VELOCITY", time_ephemeris_dim],
|
|
233
234
|
# optional: data NORTH_POLE_POSITION_ANGLE and NORTH_POLE_ANGULAR_DISTANCE
|
|
234
|
-
"NP_ang": ["NORTH_POLE_POSITION_ANGLE",
|
|
235
|
-
"NP_dist": ["NORTH_POLE_ANGULAR_DISTANCE",
|
|
235
|
+
"NP_ang": ["NORTH_POLE_POSITION_ANGLE", time_ephemeris_dim],
|
|
236
|
+
"NP_dist": ["NORTH_POLE_ANGULAR_DISTANCE", time_ephemeris_dim],
|
|
236
237
|
# optional: HELIOCENTRIC_RADIAL_VELOCITY
|
|
237
|
-
"rdot": ["HELIOCENTRIC_RADIAL_VELOCITY",
|
|
238
|
+
"rdot": ["HELIOCENTRIC_RADIAL_VELOCITY", time_ephemeris_dim],
|
|
238
239
|
# optional: OBSERVER_PHASE_ANGLE
|
|
239
|
-
"phang": ["OBSERVER_PHASE_ANGLE",
|
|
240
|
+
"phang": ["OBSERVER_PHASE_ANGLE", time_ephemeris_dim],
|
|
240
241
|
}
|
|
241
242
|
convert_generic_xds_to_xradio_schema(
|
|
242
243
|
ephemeris_xds, temp_xds, to_new_data_variables, {}
|
|
@@ -251,7 +252,7 @@ def extract_ephemeris_info(
|
|
|
251
252
|
"type": "quantity",
|
|
252
253
|
"units": [
|
|
253
254
|
cast_to_str(
|
|
254
|
-
|
|
255
|
+
ephemeris_column_description[generic_var_name]["keywords"][
|
|
255
256
|
unit_keyword
|
|
256
257
|
]
|
|
257
258
|
)
|
|
@@ -260,7 +261,7 @@ def extract_ephemeris_info(
|
|
|
260
261
|
)
|
|
261
262
|
|
|
262
263
|
# Add optional data: SUB_OBSERVER_POSITION and SUB_SOLAR_POSITION
|
|
263
|
-
if "DiskLong" in
|
|
264
|
+
if "DiskLong" in ephemeris_column_description:
|
|
264
265
|
key_lon = "DiskLong"
|
|
265
266
|
key_lat = "DiskLat"
|
|
266
267
|
else:
|
|
@@ -268,7 +269,7 @@ def extract_ephemeris_info(
|
|
|
268
269
|
key_lat = "diskLat"
|
|
269
270
|
|
|
270
271
|
if key_lon in ephemeris_xds.data_vars:
|
|
271
|
-
temp_xds["
|
|
272
|
+
temp_xds["SUB_OBSERVER_DIRECTION"] = xr.DataArray(
|
|
272
273
|
np.column_stack(
|
|
273
274
|
(
|
|
274
275
|
ephemeris_xds[key_lon].data,
|
|
@@ -276,10 +277,10 @@ def extract_ephemeris_info(
|
|
|
276
277
|
np.zeros(ephemeris_xds[key_lon].shape),
|
|
277
278
|
)
|
|
278
279
|
),
|
|
279
|
-
dims=["
|
|
280
|
+
dims=["time_ephemeris", "ellipsoid_pos_label"],
|
|
280
281
|
)
|
|
281
282
|
|
|
282
|
-
temp_xds["
|
|
283
|
+
temp_xds["SUB_OBSERVER_DIRECTION"].attrs.update(
|
|
283
284
|
{
|
|
284
285
|
"type": "location",
|
|
285
286
|
"ellipsoid": "NA",
|
|
@@ -287,10 +288,10 @@ def extract_ephemeris_info(
|
|
|
287
288
|
"coordinate_system": "planetodetic",
|
|
288
289
|
"units": [
|
|
289
290
|
cast_to_str(
|
|
290
|
-
|
|
291
|
+
ephemeris_column_description[key_lon]["keywords"][unit_keyword]
|
|
291
292
|
),
|
|
292
293
|
cast_to_str(
|
|
293
|
-
|
|
294
|
+
ephemeris_column_description[key_lat]["keywords"][unit_keyword]
|
|
294
295
|
),
|
|
295
296
|
"m",
|
|
296
297
|
],
|
|
@@ -306,7 +307,7 @@ def extract_ephemeris_info(
|
|
|
306
307
|
ephemeris_xds["r"].data,
|
|
307
308
|
)
|
|
308
309
|
),
|
|
309
|
-
dims=["
|
|
310
|
+
dims=["time_ephemeris", "ellipsoid_pos_label"],
|
|
310
311
|
)
|
|
311
312
|
temp_xds["SUB_SOLAR_POSITION"].attrs.update(
|
|
312
313
|
{
|
|
@@ -316,22 +317,22 @@ def extract_ephemeris_info(
|
|
|
316
317
|
"coordinate_system": "planetodetic",
|
|
317
318
|
"units": [
|
|
318
319
|
cast_to_str(
|
|
319
|
-
|
|
320
|
+
ephemeris_column_description["SI_lon"]["keywords"][unit_keyword]
|
|
320
321
|
),
|
|
321
322
|
cast_to_str(
|
|
322
|
-
|
|
323
|
+
ephemeris_column_description["SI_lat"]["keywords"][unit_keyword]
|
|
323
324
|
),
|
|
324
325
|
cast_to_str(
|
|
325
|
-
|
|
326
|
+
ephemeris_column_description["r"]["keywords"][unit_keyword]
|
|
326
327
|
),
|
|
327
328
|
],
|
|
328
329
|
}
|
|
329
330
|
)
|
|
330
331
|
|
|
331
|
-
# We are using the "
|
|
332
|
+
# We are using the "time_ephemeris" label because it might not match the optional time axis of the source and field info. If ephemeris_interpolate=True then rename it to time.
|
|
332
333
|
coords = {
|
|
333
334
|
"ellipsoid_pos_label": ["lon", "lat", "dist"],
|
|
334
|
-
"
|
|
335
|
+
"time_ephemeris": ephemeris_xds["time"].data,
|
|
335
336
|
"sky_pos_label": ["ra", "dec", "dist"],
|
|
336
337
|
}
|
|
337
338
|
temp_xds = temp_xds.assign_coords(coords)
|
|
@@ -341,21 +342,21 @@ def extract_ephemeris_info(
|
|
|
341
342
|
"scale": "UTC",
|
|
342
343
|
"format": "UNIX",
|
|
343
344
|
}
|
|
344
|
-
temp_xds["
|
|
345
|
+
temp_xds["time_ephemeris"].attrs.update(time_coord_attrs)
|
|
345
346
|
|
|
346
347
|
# Convert to si units and interpolate if ephemeris_interpolate=True:
|
|
347
348
|
temp_xds = convert_to_si_units(temp_xds)
|
|
348
349
|
temp_xds = interpolate_to_time(
|
|
349
|
-
temp_xds, interp_time, "field_and_source_xds", time_name="
|
|
350
|
+
temp_xds, interp_time, "field_and_source_xds", time_name="time_ephemeris"
|
|
350
351
|
)
|
|
351
352
|
|
|
352
|
-
# If we interpolate rename the
|
|
353
|
+
# If we interpolate rename the time_ephemeris axis to time.
|
|
353
354
|
if interp_time is not None:
|
|
354
|
-
time_coord = {"time": ("
|
|
355
|
+
time_coord = {"time": ("time_ephemeris", interp_time.data)}
|
|
355
356
|
temp_xds = temp_xds.assign_coords(time_coord)
|
|
356
357
|
temp_xds.coords["time"].attrs.update(time_coord_attrs)
|
|
357
|
-
temp_xds = temp_xds.swap_dims({"
|
|
358
|
-
"
|
|
358
|
+
temp_xds = temp_xds.swap_dims({"time_ephemeris": "time"}).drop_vars(
|
|
359
|
+
"time_ephemeris"
|
|
359
360
|
)
|
|
360
361
|
|
|
361
362
|
xds = xr.merge([xds, temp_xds])
|