xradio 0.0.33__py3-none-any.whl → 0.0.36__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/_utils/list_and_array.py +3 -1
- xradio/_utils/schema.py +190 -0
- xradio/_utils/zarr/common.py +11 -5
- xradio/image/_util/_zarr/xds_from_zarr.py +15 -2
- xradio/image/_util/_zarr/zarr_low_level.py +65 -14
- xradio/schema/bases.py +37 -8
- xradio/schema/check.py +15 -3
- xradio/schema/dataclass.py +2 -2
- xradio/vis/_processing_set.py +136 -10
- xradio/vis/_vis_utils/_ms/_tables/read.py +9 -0
- xradio/vis/_vis_utils/_ms/conversion.py +166 -116
- xradio/vis/_vis_utils/_ms/create_antenna_xds.py +479 -0
- xradio/vis/_vis_utils/_ms/create_field_and_source_xds.py +84 -42
- xradio/vis/_vis_utils/_ms/msv2_to_msv4_meta.py +1 -105
- xradio/vis/_vis_utils/_ms/msv4_sub_xdss.py +4 -224
- xradio/vis/_vis_utils/_utils/xds_helper.py +10 -2
- xradio/vis/convert_msv2_to_processing_set.py +6 -1
- xradio/vis/load_processing_set.py +2 -2
- xradio/vis/read_processing_set.py +5 -2
- xradio/vis/schema.py +348 -112
- {xradio-0.0.33.dist-info → xradio-0.0.36.dist-info}/METADATA +1 -1
- {xradio-0.0.33.dist-info → xradio-0.0.36.dist-info}/RECORD +25 -23
- {xradio-0.0.33.dist-info → xradio-0.0.36.dist-info}/WHEEL +1 -1
- {xradio-0.0.33.dist-info → xradio-0.0.36.dist-info}/LICENSE.txt +0 -0
- {xradio-0.0.33.dist-info → xradio-0.0.36.dist-info}/top_level.txt +0 -0
|
@@ -5,9 +5,7 @@ from typing import Tuple, Union
|
|
|
5
5
|
import numpy as np
|
|
6
6
|
import xarray as xr
|
|
7
7
|
|
|
8
|
-
from xradio.
|
|
9
|
-
column_description_casacore_to_msv4_measure,
|
|
10
|
-
)
|
|
8
|
+
from xradio._utils.schema import column_description_casacore_to_msv4_measure
|
|
11
9
|
from xradio.vis._vis_utils._ms.msv4_sub_xdss import interpolate_to_time
|
|
12
10
|
from xradio.vis._vis_utils._ms.subtables import subt_rename_ids
|
|
13
11
|
from xradio.vis._vis_utils._ms._tables.read import (
|
|
@@ -46,6 +44,10 @@ def create_field_and_source_xds(
|
|
|
46
44
|
The field ids to select.
|
|
47
45
|
spectral_window_id : int
|
|
48
46
|
The ID of the spectral window.
|
|
47
|
+
field_times: list
|
|
48
|
+
Time data for field. It is the same as the time axis in the main MSv4 dataset and is used if more than one field is present.
|
|
49
|
+
is_single_dish: bool
|
|
50
|
+
whether the main xds has single-dish (SPECTRUM) data
|
|
49
51
|
time_min_max : Tuple[np.float64, np.float46]
|
|
50
52
|
Min / max times to constrain loading (usually to the time range relevant to an MSv4)
|
|
51
53
|
ephemeris_interp_time : Union[xr.DataArray, None]
|
|
@@ -62,7 +64,7 @@ def create_field_and_source_xds(
|
|
|
62
64
|
field_and_source_xds = xr.Dataset()
|
|
63
65
|
|
|
64
66
|
field_and_source_xds, ephemeris_path, ephemeris_table_name, source_id = (
|
|
65
|
-
|
|
67
|
+
extract_field_info_and_check_ephemeris(
|
|
66
68
|
field_and_source_xds, in_file, field_id, field_times, is_single_dish
|
|
67
69
|
)
|
|
68
70
|
)
|
|
@@ -77,7 +79,7 @@ def create_field_and_source_xds(
|
|
|
77
79
|
ephemeris_interp_time,
|
|
78
80
|
)
|
|
79
81
|
|
|
80
|
-
field_and_source_xds = extract_source_info(
|
|
82
|
+
field_and_source_xds, num_lines = extract_source_info(
|
|
81
83
|
field_and_source_xds, in_file, source_id, spectral_window_id
|
|
82
84
|
)
|
|
83
85
|
|
|
@@ -95,7 +97,7 @@ def create_field_and_source_xds(
|
|
|
95
97
|
if np.unique(field_and_source_xds[center_dv], axis=0).shape[0] == 1:
|
|
96
98
|
field_and_source_xds = field_and_source_xds.isel(time=0).drop_vars("time")
|
|
97
99
|
|
|
98
|
-
return field_and_source_xds, source_id
|
|
100
|
+
return field_and_source_xds, source_id, num_lines
|
|
99
101
|
|
|
100
102
|
|
|
101
103
|
def extract_ephemeris_info(
|
|
@@ -119,7 +121,7 @@ def extract_ephemeris_info(
|
|
|
119
121
|
The name of the ephemeris table.
|
|
120
122
|
time_min_max : Tuple[np.float46, np.float64]
|
|
121
123
|
Min / max times to constrain loading (usually to the time range relevant to an MSv4)
|
|
122
|
-
|
|
124
|
+
interp_time : Union[xr.DataArray, None]
|
|
123
125
|
Time axis to interpolate the data vars to (usually main MSv4 time)
|
|
124
126
|
|
|
125
127
|
Returns:
|
|
@@ -172,18 +174,17 @@ def extract_ephemeris_info(
|
|
|
172
174
|
else:
|
|
173
175
|
unit_keyword = "QuantumUnits"
|
|
174
176
|
|
|
177
|
+
# We are using the "time_ephemeris_axis" 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.
|
|
175
178
|
coords = {
|
|
176
179
|
"ellipsoid_pos_label": ["lon", "lat", "dist"],
|
|
177
|
-
"
|
|
178
|
-
"time"
|
|
179
|
-
].data, # We are using the "ephem_time" 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.
|
|
180
|
+
"time_ephemeris_axis": ephemeris_xds["time"].data,
|
|
180
181
|
"sky_pos_label": ["ra", "dec", "dist"],
|
|
181
182
|
}
|
|
182
183
|
|
|
183
184
|
temp_xds = xr.Dataset()
|
|
184
185
|
|
|
185
|
-
# Add mandatory data:
|
|
186
|
-
temp_xds["
|
|
186
|
+
# Add mandatory data: SOURCE_LOCATION (POSITION / sky_pos_label)
|
|
187
|
+
temp_xds["SOURCE_LOCATION"] = xr.DataArray(
|
|
187
188
|
np.column_stack(
|
|
188
189
|
(
|
|
189
190
|
ephemeris_xds["RA"].data,
|
|
@@ -191,7 +192,7 @@ def extract_ephemeris_info(
|
|
|
191
192
|
ephemeris_xds["Rho"].data,
|
|
192
193
|
)
|
|
193
194
|
),
|
|
194
|
-
dims=["
|
|
195
|
+
dims=["time_ephemeris_axis", "sky_pos_label"],
|
|
195
196
|
)
|
|
196
197
|
# Have to use cast_to_str because the ephemeris table units are not consistently in a list or a string.
|
|
197
198
|
sky_coord_units = [
|
|
@@ -199,13 +200,13 @@ def extract_ephemeris_info(
|
|
|
199
200
|
cast_to_str(ephemris_column_description["DEC"]["keywords"][unit_keyword]),
|
|
200
201
|
cast_to_str(ephemris_column_description["Rho"]["keywords"][unit_keyword]),
|
|
201
202
|
]
|
|
202
|
-
temp_xds["
|
|
203
|
+
temp_xds["SOURCE_LOCATION"].attrs.update(
|
|
203
204
|
{"type": "sky_coord", "frame": sky_coord_frame, "units": sky_coord_units}
|
|
204
205
|
)
|
|
205
206
|
|
|
206
207
|
# Add mandatory data: SOURCE_RADIAL_VELOCITY
|
|
207
208
|
temp_xds["SOURCE_RADIAL_VELOCITY"] = xr.DataArray(
|
|
208
|
-
ephemeris_xds["RadVel"].data, dims=["
|
|
209
|
+
ephemeris_xds["RadVel"].data, dims=["time_ephemeris_axis"]
|
|
209
210
|
)
|
|
210
211
|
temp_xds["SOURCE_RADIAL_VELOCITY"].attrs.update(
|
|
211
212
|
{
|
|
@@ -241,7 +242,7 @@ def extract_ephemeris_info(
|
|
|
241
242
|
# Add optional data NORTH_POLE_POSITION_ANGLE and NORTH_POLE_ANGULAR_DISTANCE
|
|
242
243
|
if "NP_ang" in ephemeris_xds.data_vars:
|
|
243
244
|
temp_xds["NORTH_POLE_POSITION_ANGLE"] = xr.DataArray(
|
|
244
|
-
ephemeris_xds["NP_ang"].data, dims=["
|
|
245
|
+
ephemeris_xds["NP_ang"].data, dims=["time_ephemeris_axis"]
|
|
245
246
|
)
|
|
246
247
|
temp_xds["NORTH_POLE_POSITION_ANGLE"].attrs.update(
|
|
247
248
|
{
|
|
@@ -256,7 +257,7 @@ def extract_ephemeris_info(
|
|
|
256
257
|
|
|
257
258
|
if "NP_dist" in ephemeris_xds.data_vars:
|
|
258
259
|
temp_xds["NORTH_POLE_ANGULAR_DISTANCE"] = xr.DataArray(
|
|
259
|
-
ephemeris_xds["NP_dist"].data, dims=["
|
|
260
|
+
ephemeris_xds["NP_dist"].data, dims=["time_ephemeris_axis"]
|
|
260
261
|
)
|
|
261
262
|
temp_xds["NORTH_POLE_ANGULAR_DISTANCE"].attrs.update(
|
|
262
263
|
{
|
|
@@ -286,7 +287,7 @@ def extract_ephemeris_info(
|
|
|
286
287
|
np.zeros(ephemeris_xds[key_lon].shape),
|
|
287
288
|
)
|
|
288
289
|
),
|
|
289
|
-
dims=["
|
|
290
|
+
dims=["time_ephemeris_axis", "ellipsoid_pos_label"],
|
|
290
291
|
)
|
|
291
292
|
|
|
292
293
|
temp_xds["SUB_OBSERVER_POSITION"].attrs.update(
|
|
@@ -316,7 +317,7 @@ def extract_ephemeris_info(
|
|
|
316
317
|
ephemeris_xds["r"].data,
|
|
317
318
|
)
|
|
318
319
|
),
|
|
319
|
-
dims=["
|
|
320
|
+
dims=["time_ephemeris_axis", "ellipsoid_pos_label"],
|
|
320
321
|
)
|
|
321
322
|
temp_xds["SUB_SOLAR_POSITION"].attrs.update(
|
|
322
323
|
{
|
|
@@ -341,7 +342,7 @@ def extract_ephemeris_info(
|
|
|
341
342
|
# Add optional data: HELIOCENTRIC_RADIAL_VELOCITY
|
|
342
343
|
if "rdot" in ephemeris_xds.data_vars:
|
|
343
344
|
temp_xds["HELIOCENTRIC_RADIAL_VELOCITY"] = xr.DataArray(
|
|
344
|
-
ephemeris_xds["rdot"].data, dims=["
|
|
345
|
+
ephemeris_xds["rdot"].data, dims=["time_ephemeris_axis"]
|
|
345
346
|
)
|
|
346
347
|
temp_xds["HELIOCENTRIC_RADIAL_VELOCITY"].attrs.update(
|
|
347
348
|
{
|
|
@@ -357,7 +358,7 @@ def extract_ephemeris_info(
|
|
|
357
358
|
# Add optional data: OBSERVER_PHASE_ANGLE
|
|
358
359
|
if "phang" in ephemeris_xds.data_vars:
|
|
359
360
|
temp_xds["OBSERVER_PHASE_ANGLE"] = xr.DataArray(
|
|
360
|
-
ephemeris_xds["phang"].data, dims=["
|
|
361
|
+
ephemeris_xds["phang"].data, dims=["time_ephemeris_axis"]
|
|
361
362
|
)
|
|
362
363
|
temp_xds["OBSERVER_PHASE_ANGLE"].attrs.update(
|
|
363
364
|
{
|
|
@@ -371,24 +372,33 @@ def extract_ephemeris_info(
|
|
|
371
372
|
)
|
|
372
373
|
|
|
373
374
|
temp_xds = temp_xds.assign_coords(coords)
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
375
|
+
time_coord_attrs = {
|
|
376
|
+
"type": "time",
|
|
377
|
+
"units": ["s"],
|
|
378
|
+
"scale": "UTC",
|
|
379
|
+
"format": "UNIX",
|
|
380
|
+
}
|
|
381
|
+
temp_xds["time_ephemeris_axis"].attrs.update(time_coord_attrs)
|
|
377
382
|
|
|
378
383
|
# Convert to si units and interpolate if ephemeris_interpolate=True:
|
|
379
384
|
temp_xds = convert_to_si_units(temp_xds)
|
|
380
385
|
temp_xds = interpolate_to_time(
|
|
381
|
-
temp_xds, interp_time, "field_and_source_xds", time_name="
|
|
386
|
+
temp_xds, interp_time, "field_and_source_xds", time_name="time_ephemeris_axis"
|
|
382
387
|
)
|
|
383
388
|
|
|
384
|
-
# If we interpolate rename the
|
|
389
|
+
# If we interpolate rename the time_ephemeris_axis axis to time.
|
|
385
390
|
if interp_time is not None:
|
|
386
|
-
|
|
391
|
+
time_coord = {"time": ("time_ephemeris_axis", interp_time.data)}
|
|
392
|
+
temp_xds = temp_xds.assign_coords(time_coord)
|
|
393
|
+
temp_xds.coords["time"].attrs.update(time_coord_attrs)
|
|
394
|
+
temp_xds = temp_xds.swap_dims({"time_ephemeris_axis": "time"}).drop_vars(
|
|
395
|
+
"time_ephemeris_axis"
|
|
396
|
+
)
|
|
387
397
|
|
|
388
398
|
xds = xr.merge([xds, temp_xds])
|
|
389
399
|
|
|
390
|
-
# Add the
|
|
391
|
-
# We also need to add a distance dimension to the FIELD_PHASE_CENTER or FIELD_REFERENCE_CENTER to match the
|
|
400
|
+
# Add the SOURCE_LOCATION to the FIELD_PHASE_CENTER or FIELD_REFERENCE_CENTER. Ephemeris obs: When loaded from the MSv2 field table the FIELD_REFERENCE_CENTER or FIELD_PHASE_CENTER only contain an offset from the SOURCE_LOCATION.
|
|
401
|
+
# We also need to add a distance dimension to the FIELD_PHASE_CENTER or FIELD_REFERENCE_CENTER to match the SOURCE_LOCATION.
|
|
392
402
|
# FIELD_PHASE_CENTER is used for interferometer data and FIELD_REFERENCE_CENTER is used for single dish data.
|
|
393
403
|
if is_single_dish:
|
|
394
404
|
center_dv = "FIELD_REFERENCE_CENTER"
|
|
@@ -405,20 +415,20 @@ def extract_ephemeris_info(
|
|
|
405
415
|
np.column_stack(
|
|
406
416
|
(xds[center_dv].values, np.zeros(xds[center_dv].values.shape[0]))
|
|
407
417
|
),
|
|
408
|
-
xds["
|
|
418
|
+
xds["SOURCE_LOCATION"].values,
|
|
409
419
|
),
|
|
410
|
-
dims=[xds["
|
|
420
|
+
dims=[xds["SOURCE_LOCATION"].dims[0], "sky_pos_label"],
|
|
411
421
|
)
|
|
412
422
|
else:
|
|
413
423
|
xds[center_dv] = xr.DataArray(
|
|
414
424
|
add_position_offsets(
|
|
415
425
|
np.append(xds[center_dv].values, 0),
|
|
416
|
-
xds["
|
|
426
|
+
xds["SOURCE_LOCATION"].values,
|
|
417
427
|
),
|
|
418
|
-
dims=[xds["
|
|
428
|
+
dims=[xds["SOURCE_LOCATION"].dims[0], "sky_pos_label"],
|
|
419
429
|
)
|
|
420
430
|
|
|
421
|
-
xds[center_dv].attrs.update(xds["
|
|
431
|
+
xds[center_dv].attrs.update(xds["SOURCE_LOCATION"].attrs)
|
|
422
432
|
|
|
423
433
|
return xds
|
|
424
434
|
|
|
@@ -442,6 +452,8 @@ def extract_source_info(xds, path, source_id, spectral_window_id):
|
|
|
442
452
|
-------
|
|
443
453
|
xds : xr.Dataset
|
|
444
454
|
The xarray dataset with the added source information.
|
|
455
|
+
num_lines : int
|
|
456
|
+
Sum of num_lines for all unique sources extracted.
|
|
445
457
|
"""
|
|
446
458
|
coords = {}
|
|
447
459
|
is_ephemeris = xds.attrs[
|
|
@@ -455,7 +467,14 @@ def extract_source_info(xds, path, source_id, spectral_window_id):
|
|
|
455
467
|
xds = xds.assign_coords(
|
|
456
468
|
{"source_name": "Unknown"}
|
|
457
469
|
) # Need to add this for ps.summary() to work.
|
|
458
|
-
return xds
|
|
470
|
+
return xds, 0
|
|
471
|
+
|
|
472
|
+
if not os.path.isdir(os.path.join(path, "SOURCE")):
|
|
473
|
+
logger.warning(
|
|
474
|
+
f"Could not find SOURCE table for source_id {source_id}. Source information will not be included in the field_and_source_xds."
|
|
475
|
+
)
|
|
476
|
+
xds = xds.assign_coords({"source_name": "Unknown"})
|
|
477
|
+
return xds, 0
|
|
459
478
|
|
|
460
479
|
unique_source_id = unique_1d(source_id)
|
|
461
480
|
taql_where = f"where (SOURCE_ID IN [{','.join(map(str, unique_source_id))}]) AND (SPECTRAL_WINDOW_ID = {spectral_window_id})"
|
|
@@ -474,7 +493,7 @@ def extract_source_info(xds, path, source_id, spectral_window_id):
|
|
|
474
493
|
xds = xds.assign_coords(
|
|
475
494
|
{"source_name": "Unknown"}
|
|
476
495
|
) # Need to add this for ps.summary() to work.
|
|
477
|
-
return xds
|
|
496
|
+
return xds, 0
|
|
478
497
|
|
|
479
498
|
assert (
|
|
480
499
|
len(source_xds.SPECTRAL_WINDOW_ID) == 1
|
|
@@ -530,8 +549,12 @@ def extract_source_info(xds, path, source_id, spectral_window_id):
|
|
|
530
549
|
else:
|
|
531
550
|
direction_var = source_xds[direction_msv2_col]
|
|
532
551
|
|
|
533
|
-
|
|
534
|
-
xds["
|
|
552
|
+
# SOURCE_LOCATION (DIRECTION / sky_dir_label)
|
|
553
|
+
xds["SOURCE_LOCATION"] = xr.DataArray(direction_var.data, dims=direction_dims)
|
|
554
|
+
location_msv4_measure = column_description_casacore_to_msv4_measure(
|
|
555
|
+
source_column_description[direction_msv2_col]
|
|
556
|
+
)
|
|
557
|
+
xds["SOURCE_LOCATION"].attrs.update(location_msv4_measure)
|
|
535
558
|
|
|
536
559
|
# Do we have line data:
|
|
537
560
|
if source_xds["NUM_LINES"].data.ndim == 0:
|
|
@@ -557,12 +580,19 @@ def extract_source_info(xds, path, source_id, spectral_window_id):
|
|
|
557
580
|
transition_var_data, max(transition_var_data.shape, vars_shape)
|
|
558
581
|
)
|
|
559
582
|
|
|
583
|
+
line_label_data = np.arange(coords_lines_data.shape[-1]).astype(str)
|
|
560
584
|
if len(source_id) == 1:
|
|
561
|
-
coords_lines = {
|
|
585
|
+
coords_lines = {
|
|
586
|
+
"line_name": ("line_label", coords_lines_data),
|
|
587
|
+
"line_label": line_label_data,
|
|
588
|
+
}
|
|
562
589
|
xds = xds.assign_coords(coords_lines)
|
|
563
590
|
line_dims = ["line_label"]
|
|
564
591
|
else:
|
|
565
|
-
coords_lines = {
|
|
592
|
+
coords_lines = {
|
|
593
|
+
"line_name": (("time", "line_label"), coords_lines_data),
|
|
594
|
+
"line_label": line_label_data,
|
|
595
|
+
}
|
|
566
596
|
xds = xds.assign_coords(coords_lines)
|
|
567
597
|
line_dims = ["time", "line_label"]
|
|
568
598
|
|
|
@@ -594,10 +624,13 @@ def extract_source_info(xds, path, source_id, spectral_window_id):
|
|
|
594
624
|
pass
|
|
595
625
|
|
|
596
626
|
xds = xds.assign_coords(coords)
|
|
597
|
-
return xds
|
|
598
627
|
|
|
628
|
+
_, unique_source_ids_indices = np.unique(source_xds.SOURCE_ID, return_index=True)
|
|
599
629
|
|
|
600
|
-
|
|
630
|
+
return xds, np.sum(num_lines[unique_source_ids_indices])
|
|
631
|
+
|
|
632
|
+
|
|
633
|
+
def extract_field_info_and_check_ephemeris(
|
|
601
634
|
field_and_source_xds, in_file, field_id, field_times, is_single_dish
|
|
602
635
|
):
|
|
603
636
|
"""
|
|
@@ -738,4 +771,13 @@ def create_field_info_and_check_ephemeris(
|
|
|
738
771
|
field_and_source_xds[msv4_name].attrs["type"] = field_measures_type
|
|
739
772
|
|
|
740
773
|
field_and_source_xds = field_and_source_xds.assign_coords(coords)
|
|
774
|
+
if "time" in field_and_source_xds:
|
|
775
|
+
time_column_description = field_xds.attrs["other"]["msv2"]["ctds_attrs"][
|
|
776
|
+
"column_descriptions"
|
|
777
|
+
]["TIME"]
|
|
778
|
+
time_msv4_measure = column_description_casacore_to_msv4_measure(
|
|
779
|
+
time_column_description
|
|
780
|
+
)
|
|
781
|
+
field_and_source_xds.coords["time"].attrs.update(time_msv4_measure)
|
|
782
|
+
|
|
741
783
|
return field_and_source_xds, ephemeris_path, ephemeris_table_name, source_id
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import graphviper.utils.logger as logger
|
|
2
|
+
from xradio._utils.schema import column_description_casacore_to_msv4_measure
|
|
2
3
|
|
|
3
4
|
col_to_data_variable_names = {
|
|
4
5
|
"FLOAT_DATA": "SPECTRUM",
|
|
@@ -30,111 +31,6 @@ col_to_coord_names = {
|
|
|
30
31
|
"ANTENNA2": "baseline_ant2_id",
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
# Map casacore measures to astropy
|
|
34
|
-
casacore_to_msv4_measure_type = {
|
|
35
|
-
"quanta": {
|
|
36
|
-
"type": "quantity",
|
|
37
|
-
},
|
|
38
|
-
"direction": {"type": "sky_coord", "Ref": "frame", "Ref_map": {"J2000": "fk5"}},
|
|
39
|
-
"epoch": {"type": "time", "Ref": "scale", "Ref_map": {"UTC": "utc"}},
|
|
40
|
-
"frequency": {
|
|
41
|
-
"type": "spectral_coord",
|
|
42
|
-
"Ref": "frame",
|
|
43
|
-
"Ref_map": {
|
|
44
|
-
"REST": "REST",
|
|
45
|
-
"LSRK": "LSRK",
|
|
46
|
-
"LSRD": "LSRD",
|
|
47
|
-
"BARY": "BARY",
|
|
48
|
-
"GEO": "GEO",
|
|
49
|
-
"TOPO": "TOPO",
|
|
50
|
-
"GALACTO": "GALACTO",
|
|
51
|
-
"LGROUP": "LGROUP",
|
|
52
|
-
"CMB": "CMB",
|
|
53
|
-
"Undefined": "Undefined",
|
|
54
|
-
},
|
|
55
|
-
},
|
|
56
|
-
"position": {
|
|
57
|
-
"type": "earth_location",
|
|
58
|
-
"Ref": "ellipsoid",
|
|
59
|
-
"Ref_map": {"ITRF": "GRS80"},
|
|
60
|
-
},
|
|
61
|
-
"uvw": {"type": "uvw", "Ref": "frame", "Ref_map": {"ITRF": "GRS80"}},
|
|
62
|
-
"radialvelocity": {"type": "quantity"},
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
casa_frequency_frames = [
|
|
66
|
-
"REST",
|
|
67
|
-
"LSRK",
|
|
68
|
-
"LSRD",
|
|
69
|
-
"BARY",
|
|
70
|
-
"GEO",
|
|
71
|
-
"TOPO",
|
|
72
|
-
"GALACTO",
|
|
73
|
-
"LGROUP",
|
|
74
|
-
"CMB",
|
|
75
|
-
"Undefined",
|
|
76
|
-
]
|
|
77
|
-
|
|
78
|
-
casa_frequency_frames_codes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 64]
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
def column_description_casacore_to_msv4_measure(
|
|
82
|
-
casacore_column_description, ref_code=None, time_format="UNIX"
|
|
83
|
-
):
|
|
84
|
-
import numpy as np
|
|
85
|
-
|
|
86
|
-
msv4_measure = {}
|
|
87
|
-
if "MEASINFO" in casacore_column_description["keywords"]:
|
|
88
|
-
measinfo = casacore_column_description["keywords"]["MEASINFO"]
|
|
89
|
-
|
|
90
|
-
# Get conversion information
|
|
91
|
-
msv4_measure_conversion = casacore_to_msv4_measure_type[measinfo["type"]]
|
|
92
|
-
|
|
93
|
-
# Convert type, copy unit
|
|
94
|
-
msv4_measure["type"] = msv4_measure_conversion["type"]
|
|
95
|
-
msv4_measure["units"] = list(
|
|
96
|
-
casacore_column_description["keywords"]["QuantumUnits"]
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
# Reference frame to convert?
|
|
100
|
-
if "Ref" in msv4_measure_conversion:
|
|
101
|
-
# Find reference frame
|
|
102
|
-
if "TabRefCodes" in measinfo:
|
|
103
|
-
ref_index = np.where(measinfo["TabRefCodes"] == ref_code)[0][0]
|
|
104
|
-
casa_ref = measinfo["TabRefTypes"][ref_index]
|
|
105
|
-
elif "Ref" in measinfo:
|
|
106
|
-
casa_ref = measinfo["Ref"]
|
|
107
|
-
elif measinfo["type"] == "frequency":
|
|
108
|
-
# Some MSv2 don't have the "TabRefCodes".
|
|
109
|
-
ref_index = np.where(casa_frequency_frames_codes == ref_code)[0][0]
|
|
110
|
-
casa_ref = casa_frequency_frames[ref_index]
|
|
111
|
-
else:
|
|
112
|
-
logger.debug(
|
|
113
|
-
f"Could not determine {measinfo['type']} measure "
|
|
114
|
-
"reference frame!"
|
|
115
|
-
)
|
|
116
|
-
|
|
117
|
-
# Convert into MSv4 representation of reference frame, warn if unknown
|
|
118
|
-
if casa_ref in msv4_measure_conversion.get("Ref_map", {}):
|
|
119
|
-
casa_ref = msv4_measure_conversion["Ref_map"][casa_ref]
|
|
120
|
-
else:
|
|
121
|
-
logger.debug(
|
|
122
|
-
f"Unknown reference frame for {measinfo['type']} "
|
|
123
|
-
f"measure, using verbatim: {casa_ref}"
|
|
124
|
-
)
|
|
125
|
-
|
|
126
|
-
msv4_measure[msv4_measure_conversion["Ref"]] = casa_ref
|
|
127
|
-
|
|
128
|
-
if msv4_measure["type"] == "time":
|
|
129
|
-
msv4_measure["format"] = time_format
|
|
130
|
-
elif "QuantumUnits" in casacore_column_description["keywords"]:
|
|
131
|
-
msv4_measure = {
|
|
132
|
-
"type": "quantity",
|
|
133
|
-
"units": list(casacore_column_description["keywords"]["QuantumUnits"]),
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
return msv4_measure
|
|
137
|
-
|
|
138
34
|
|
|
139
35
|
def create_attribute_metadata(col, main_column_descriptions):
|
|
140
36
|
attrs_metadata = column_description_casacore_to_msv4_measure(
|