xradio 1.0.2__py3-none-any.whl → 1.1.0__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/_casacore/casacore_from_casatools.py +1 -1
- xradio/_utils/dict_helpers.py +38 -7
- xradio/_utils/list_and_array.py +26 -3
- xradio/_utils/schema.py +44 -0
- xradio/_utils/xarray_helpers.py +63 -0
- xradio/_utils/zarr/common.py +4 -2
- xradio/image/__init__.py +4 -2
- xradio/image/_util/_casacore/common.py +2 -1
- xradio/image/_util/_casacore/xds_from_casacore.py +105 -51
- xradio/image/_util/_casacore/xds_to_casacore.py +117 -52
- xradio/image/_util/_fits/xds_from_fits.py +124 -36
- xradio/image/_util/_zarr/common.py +0 -1
- xradio/image/_util/casacore.py +133 -16
- xradio/image/_util/common.py +6 -5
- xradio/image/_util/image_factory.py +466 -27
- xradio/image/image.py +72 -100
- xradio/image/image_xds.py +262 -0
- xradio/image/schema.py +85 -0
- xradio/measurement_set/__init__.py +5 -4
- xradio/measurement_set/_utils/_msv2/_tables/read.py +7 -3
- xradio/measurement_set/_utils/_msv2/conversion.py +6 -9
- xradio/measurement_set/_utils/_msv2/create_field_and_source_xds.py +1 -0
- xradio/measurement_set/_utils/_msv2/msv4_sub_xdss.py +1 -1
- xradio/measurement_set/_utils/_utils/interpolate.py +5 -0
- xradio/measurement_set/_utils/_utils/partition_attrs.py +0 -1
- xradio/measurement_set/convert_msv2_to_processing_set.py +9 -9
- xradio/measurement_set/load_processing_set.py +2 -2
- xradio/measurement_set/measurement_set_xdt.py +83 -93
- xradio/measurement_set/open_processing_set.py +1 -1
- xradio/measurement_set/processing_set_xdt.py +33 -26
- xradio/schema/check.py +70 -19
- xradio/schema/common.py +0 -1
- xradio/testing/__init__.py +0 -0
- xradio/testing/_utils/__template__.py +58 -0
- xradio/testing/measurement_set/__init__.py +58 -0
- xradio/testing/measurement_set/checker.py +131 -0
- xradio/testing/measurement_set/io.py +22 -0
- xradio/testing/measurement_set/msv2_io.py +1854 -0
- {xradio-1.0.2.dist-info → xradio-1.1.0.dist-info}/METADATA +64 -23
- xradio-1.1.0.dist-info/RECORD +75 -0
- {xradio-1.0.2.dist-info → xradio-1.1.0.dist-info}/WHEEL +1 -1
- xradio-1.0.2.dist-info/RECORD +0 -66
- {xradio-1.0.2.dist-info → xradio-1.1.0.dist-info}/licenses/LICENSE.txt +0 -0
- {xradio-1.0.2.dist-info → xradio-1.1.0.dist-info}/top_level.txt +0 -0
xradio/_utils/dict_helpers.py
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
from xradio._utils.list_and_array import to_python_type
|
|
2
|
+
|
|
3
|
+
|
|
1
4
|
def make_quantity(value, units: str, dims: list = []) -> dict:
|
|
2
5
|
"""
|
|
3
6
|
create a quantity dictionary given value and units
|
|
@@ -13,7 +16,11 @@ def make_quantity(value, units: str, dims: list = []) -> dict:
|
|
|
13
16
|
-------
|
|
14
17
|
dict
|
|
15
18
|
"""
|
|
16
|
-
return {
|
|
19
|
+
return {
|
|
20
|
+
"data": to_python_type(value),
|
|
21
|
+
"dims": dims,
|
|
22
|
+
"attrs": make_quantity_attrs(units),
|
|
23
|
+
}
|
|
17
24
|
|
|
18
25
|
|
|
19
26
|
def ensure_units_are_consistent(units):
|
|
@@ -67,7 +74,7 @@ def make_spectral_coord_reference_dict(
|
|
|
67
74
|
u,
|
|
68
75
|
observer.lower() if observer not in ["TOPO", "BARY", "REST"] else observer,
|
|
69
76
|
),
|
|
70
|
-
"data": value,
|
|
77
|
+
"data": to_python_type(value),
|
|
71
78
|
"dims": [],
|
|
72
79
|
}
|
|
73
80
|
|
|
@@ -98,14 +105,38 @@ def make_skycoord_dict(data: list[float], units: str, frame: str) -> dict:
|
|
|
98
105
|
"type": "sky_coord",
|
|
99
106
|
"units": ensure_units_are_consistent(units),
|
|
100
107
|
},
|
|
101
|
-
"data": data,
|
|
102
|
-
"dims":
|
|
108
|
+
"data": to_python_type(data),
|
|
109
|
+
"dims": "sky_dir_label",
|
|
110
|
+
"coords": {"sky_dir_label": {"data": ["ra", "dec"], "dims": "sky_dir_label"}},
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def make_direction_location_dict(data: list[float], units: str, frame: str) -> dict:
|
|
115
|
+
return {
|
|
116
|
+
"attrs": {
|
|
117
|
+
"frame": frame.upper(),
|
|
118
|
+
"type": "location",
|
|
119
|
+
"units": ensure_units_are_consistent(units),
|
|
120
|
+
},
|
|
121
|
+
"data": to_python_type(data),
|
|
122
|
+
"dims": "ellipsoid_dir_label",
|
|
123
|
+
"coords": {
|
|
124
|
+
"ellipsoid_dir_label": {
|
|
125
|
+
"data": ["lon", "lat"],
|
|
126
|
+
"dims": "ellipsoid_dir_label",
|
|
127
|
+
}
|
|
128
|
+
},
|
|
103
129
|
}
|
|
104
130
|
|
|
105
131
|
|
|
106
132
|
def make_time_measure_attrs(units="s", scale="utc", time_format="mjd") -> dict:
|
|
107
133
|
u = ensure_units_are_consistent(units)
|
|
108
|
-
return {
|
|
134
|
+
return {
|
|
135
|
+
"units": u,
|
|
136
|
+
"scale": scale.lower(),
|
|
137
|
+
"format": time_format.lower(),
|
|
138
|
+
"type": "time",
|
|
139
|
+
}
|
|
109
140
|
|
|
110
141
|
|
|
111
142
|
def make_time_measure_dict(data, units="s", scale="utc", time_format="mjd") -> dict:
|
|
@@ -127,7 +158,7 @@ def make_time_measure_dict(data, units="s", scale="utc", time_format="mjd") -> d
|
|
|
127
158
|
"""
|
|
128
159
|
x = {}
|
|
129
160
|
x["attrs"] = make_time_measure_attrs(units, scale, time_format)
|
|
130
|
-
x["data"] = data
|
|
161
|
+
x["data"] = to_python_type(data)
|
|
131
162
|
x["dims"] = []
|
|
132
163
|
return x
|
|
133
164
|
|
|
@@ -149,7 +180,7 @@ def make_time_coord_attrs(units="s", scale="utc", time_format="mjd") -> dict:
|
|
|
149
180
|
-------
|
|
150
181
|
dict
|
|
151
182
|
"""
|
|
152
|
-
x = make_time_measure_attrs(units, scale, time_format)
|
|
183
|
+
x = make_time_measure_attrs(units, scale.lower(), time_format.lower())
|
|
153
184
|
del x["type"]
|
|
154
185
|
return x
|
|
155
186
|
|
xradio/_utils/list_and_array.py
CHANGED
|
@@ -53,11 +53,34 @@ def get_pad_value(col_dtype: np.dtype) -> object:
|
|
|
53
53
|
)
|
|
54
54
|
|
|
55
55
|
|
|
56
|
+
def to_python_type(x):
|
|
57
|
+
"""
|
|
58
|
+
Convert any NumPy scalar, array, or nested structure to native Python types.
|
|
59
|
+
|
|
60
|
+
- np.float32, np.float64 → float
|
|
61
|
+
- np.int32, np.int64 → int
|
|
62
|
+
- np.bool_ → bool
|
|
63
|
+
- np.ndarray → list of Python-native types
|
|
64
|
+
- nested containers (list/tuple/dict) are handled recursively
|
|
65
|
+
"""
|
|
66
|
+
if isinstance(x, np.generic): # covers all numpy scalar types
|
|
67
|
+
return x.item()
|
|
68
|
+
elif isinstance(x, np.ndarray):
|
|
69
|
+
return x.tolist()
|
|
70
|
+
elif isinstance(x, (list, tuple)):
|
|
71
|
+
return type(x)(to_python_type(v) for v in x)
|
|
72
|
+
elif isinstance(x, dict):
|
|
73
|
+
return {k: to_python_type(v) for k, v in x.items()}
|
|
74
|
+
else:
|
|
75
|
+
return x
|
|
76
|
+
|
|
77
|
+
|
|
56
78
|
def to_list(x):
|
|
57
79
|
if isinstance(x, np.ndarray):
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
80
|
+
z = x.astype(float)
|
|
81
|
+
if z.ndim == 0:
|
|
82
|
+
return [z.item()]
|
|
83
|
+
return list(z) # needed for json serialization
|
|
61
84
|
elif isinstance(x, list):
|
|
62
85
|
return x
|
|
63
86
|
return [x]
|
xradio/_utils/schema.py
CHANGED
|
@@ -224,3 +224,47 @@ casa_frequency_frames = [
|
|
|
224
224
|
]
|
|
225
225
|
|
|
226
226
|
casa_frequency_frames_codes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 64]
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def get_data_group_keys(schema_name: str) -> list[tuple[str, bool]]:
|
|
230
|
+
"""Return (name, is_optional) pairs for data group keys for the given schema.
|
|
231
|
+
|
|
232
|
+
Parameters
|
|
233
|
+
----------
|
|
234
|
+
schema_name : str
|
|
235
|
+
The name of the schema to retrieve data group keys for. Supported values are "msv4" and "image".
|
|
236
|
+
|
|
237
|
+
Returns
|
|
238
|
+
-------
|
|
239
|
+
list[tuple[str, bool]]
|
|
240
|
+
A list of tuples (key_name, is_optional) for the specified schema.
|
|
241
|
+
|
|
242
|
+
Raises
|
|
243
|
+
------
|
|
244
|
+
ValueError
|
|
245
|
+
If the schema name is unknown.
|
|
246
|
+
"""
|
|
247
|
+
from typing import get_type_hints, get_origin, get_args, Union
|
|
248
|
+
|
|
249
|
+
if schema_name == "msv4":
|
|
250
|
+
from xradio.measurement_set.schema import DataGroupDict
|
|
251
|
+
|
|
252
|
+
cls = DataGroupDict
|
|
253
|
+
elif schema_name == "image":
|
|
254
|
+
from xradio.image.schema import DataGroupDict
|
|
255
|
+
|
|
256
|
+
cls = DataGroupDict
|
|
257
|
+
else:
|
|
258
|
+
raise ValueError(f"Unknown schema name: {schema_name}")
|
|
259
|
+
|
|
260
|
+
annotations = get_type_hints(cls)
|
|
261
|
+
keys_with_optional = {}
|
|
262
|
+
for name, anno in annotations.items():
|
|
263
|
+
origin = get_origin(anno)
|
|
264
|
+
is_optional = False
|
|
265
|
+
if origin is Union:
|
|
266
|
+
args = get_args(anno)
|
|
267
|
+
is_optional = type(None) in args
|
|
268
|
+
keys_with_optional[name] = is_optional
|
|
269
|
+
|
|
270
|
+
return keys_with_optional
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import xarray as xr
|
|
2
|
+
from xradio._utils.schema import get_data_group_keys
|
|
3
|
+
from collections.abc import Mapping, Iterable
|
|
4
|
+
from typing import Any, Union
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def get_data_group_name(
|
|
8
|
+
xdx: Union[xr.Dataset, xr.DataTree], data_group_name: str = None
|
|
9
|
+
) -> str:
|
|
10
|
+
|
|
11
|
+
if data_group_name is None:
|
|
12
|
+
if "base" in xdx.attrs["data_groups"]:
|
|
13
|
+
data_group_name = "base"
|
|
14
|
+
else:
|
|
15
|
+
data_group_name = list(xdx.attrs["data_groups"].keys())[0]
|
|
16
|
+
|
|
17
|
+
return data_group_name
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def create_new_data_group(
|
|
21
|
+
xdx: Union[xr.Dataset, xr.DataTree],
|
|
22
|
+
schema_name: str,
|
|
23
|
+
new_data_group_name: str,
|
|
24
|
+
data_group: dict,
|
|
25
|
+
data_group_dv_shared_with: str = None,
|
|
26
|
+
) -> xr.DataTree:
|
|
27
|
+
"""Adds a data group to Xarray Data Structure (Dataset or DataTree).
|
|
28
|
+
|
|
29
|
+
Parameters
|
|
30
|
+
----------
|
|
31
|
+
new_data_group_name : str
|
|
32
|
+
The name of the new data group to add.
|
|
33
|
+
data_group : dict
|
|
34
|
+
A dictionary containing the data group variables and their attributes.
|
|
35
|
+
data_group_dv_shared_with : str, optional
|
|
36
|
+
The name of the data group to share data variables with, by default "base"
|
|
37
|
+
|
|
38
|
+
Returns
|
|
39
|
+
-------
|
|
40
|
+
xr.DataTree
|
|
41
|
+
MSv4 DataTree with the new group added
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
data_group_dv_shared_with = get_data_group_name(xdx, data_group_dv_shared_with)
|
|
45
|
+
|
|
46
|
+
default_data_group = xdx.attrs["data_groups"][data_group_dv_shared_with]
|
|
47
|
+
|
|
48
|
+
new_data_group = {}
|
|
49
|
+
|
|
50
|
+
data_group_keys = get_data_group_keys(schema_name)
|
|
51
|
+
|
|
52
|
+
for key, optional in data_group_keys.items():
|
|
53
|
+
if key in data_group:
|
|
54
|
+
new_data_group[key] = data_group[key]
|
|
55
|
+
else:
|
|
56
|
+
if key not in default_data_group and not optional:
|
|
57
|
+
raise ValueError(
|
|
58
|
+
f"Data group key '{key}' is required but not provided and not present in shared data group '{data_group_dv_shared_with}'."
|
|
59
|
+
)
|
|
60
|
+
elif key in default_data_group:
|
|
61
|
+
new_data_group[key] = default_data_group[key]
|
|
62
|
+
|
|
63
|
+
return new_data_group_name, new_data_group
|
xradio/_utils/zarr/common.py
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import xarray as xr
|
|
2
|
-
import s3fs
|
|
3
2
|
import os
|
|
4
|
-
from botocore.exceptions import NoCredentialsError
|
|
5
3
|
|
|
6
4
|
# from xradio.vis._vis_utils._ms.msv2_to_msv4_meta import (
|
|
7
5
|
# column_description_casacore_to_msv4_measure,
|
|
@@ -10,6 +8,9 @@ from botocore.exceptions import NoCredentialsError
|
|
|
10
8
|
|
|
11
9
|
def _get_file_system_and_items(ps_store: str):
|
|
12
10
|
|
|
11
|
+
import s3fs
|
|
12
|
+
from botocore.exceptions import NoCredentialsError
|
|
13
|
+
|
|
13
14
|
# default to assuming the data are accessible on local file system
|
|
14
15
|
if os.path.isdir(ps_store):
|
|
15
16
|
# handle a common shell convention
|
|
@@ -74,6 +75,7 @@ def _open_dataset(
|
|
|
74
75
|
"""
|
|
75
76
|
|
|
76
77
|
import dask
|
|
78
|
+
import s3fs
|
|
77
79
|
|
|
78
80
|
if isinstance(file_system, s3fs.core.S3FileSystem):
|
|
79
81
|
mapping = s3fs.S3Map(root=store, s3=file_system, check=False)
|
xradio/image/__init__.py
CHANGED
|
@@ -5,15 +5,17 @@ from .image import (
|
|
|
5
5
|
make_empty_aperture_image,
|
|
6
6
|
make_empty_lmuv_image,
|
|
7
7
|
make_empty_sky_image,
|
|
8
|
-
|
|
8
|
+
open_image,
|
|
9
9
|
write_image,
|
|
10
10
|
)
|
|
11
11
|
|
|
12
|
+
from .image_xds import ImageXds
|
|
13
|
+
|
|
12
14
|
__all__ = [
|
|
13
15
|
"load_image",
|
|
14
16
|
"make_empty_aperture_image",
|
|
15
17
|
"make_empty_lmuv_image",
|
|
16
18
|
"make_empty_sky_image",
|
|
17
|
-
"
|
|
19
|
+
"open_image",
|
|
18
20
|
"write_image",
|
|
19
21
|
]
|
|
@@ -42,7 +42,8 @@ def _create_new_image(
|
|
|
42
42
|
del image
|
|
43
43
|
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
_image_flag = "flag"
|
|
46
|
+
_beam_fit_params = "beam_fit_params"
|
|
46
47
|
# _native_types = ["FREQ", "VRAD", "VOPT", "BETA", "WAVE", "AWAV"]
|
|
47
48
|
_object_name = "object_name"
|
|
48
49
|
_pointing_center = "pointing_center"
|
|
@@ -9,6 +9,7 @@ import toolviper.utils.logger as logger
|
|
|
9
9
|
import numpy as np
|
|
10
10
|
import xarray as xr
|
|
11
11
|
from astropy import units as u
|
|
12
|
+
from xradio._utils.list_and_array import to_python_type
|
|
12
13
|
|
|
13
14
|
try:
|
|
14
15
|
from casacore import tables
|
|
@@ -19,14 +20,15 @@ except ImportError:
|
|
|
19
20
|
from xradio._utils._casacore.casacore_from_casatools import image as casa_image
|
|
20
21
|
|
|
21
22
|
|
|
22
|
-
from .common import (
|
|
23
|
-
|
|
23
|
+
from xradio.image._util._casacore.common import (
|
|
24
|
+
_image_flag,
|
|
25
|
+
_beam_fit_params,
|
|
24
26
|
_object_name,
|
|
25
27
|
_open_image_ro,
|
|
26
28
|
_pointing_center,
|
|
27
29
|
)
|
|
28
30
|
|
|
29
|
-
from
|
|
31
|
+
from xradio.image._util.common import (
|
|
30
32
|
_compute_linear_world_values,
|
|
31
33
|
_compute_velocity_values,
|
|
32
34
|
_compute_world_sph_dims,
|
|
@@ -37,10 +39,11 @@ from ..common import (
|
|
|
37
39
|
_image_type,
|
|
38
40
|
_l_m_attr_notes,
|
|
39
41
|
)
|
|
40
|
-
from
|
|
42
|
+
from xradio._utils._casacore.tables import extract_table_attributes, open_table_ro
|
|
41
43
|
from xradio._utils.coord_math import _deg_to_rad
|
|
42
44
|
from xradio._utils.dict_helpers import (
|
|
43
45
|
_casacore_q_to_xradio_q,
|
|
46
|
+
make_direction_location_dict,
|
|
44
47
|
make_spectral_coord_reference_dict,
|
|
45
48
|
make_quantity,
|
|
46
49
|
make_skycoord_dict,
|
|
@@ -68,13 +71,15 @@ def _add_mask(
|
|
|
68
71
|
xda = xr.DataArray(ary, dims=dimorder)
|
|
69
72
|
# True pixels are good in numpy masked arrays
|
|
70
73
|
xda = da.logical_not(xda)
|
|
71
|
-
xda.attrs["
|
|
74
|
+
xda.attrs["type"] = "flag"
|
|
72
75
|
xda = xda.rename(name)
|
|
73
76
|
xds[xda.name] = xda
|
|
74
77
|
return xds
|
|
75
78
|
|
|
76
79
|
|
|
77
|
-
def _casa_image_to_xds_image_attrs(
|
|
80
|
+
def _casa_image_to_xds_image_attrs(
|
|
81
|
+
image: casa_image, history: bool = False, image_type: str = "SKY"
|
|
82
|
+
) -> dict:
|
|
78
83
|
"""
|
|
79
84
|
get the image attributes from the casacoreimage object
|
|
80
85
|
"""
|
|
@@ -177,20 +182,27 @@ def _casa_image_to_xds_image_attrs(image: casa_image, history: bool = True) -> d
|
|
|
177
182
|
obj = "objectname"
|
|
178
183
|
attrs[_object_name] = imageinfo[obj] if obj in imageinfo else ""
|
|
179
184
|
attrs["user"] = meta_dict["miscinfo"]
|
|
185
|
+
"""
|
|
180
186
|
defmask = "Image_defaultmask"
|
|
181
187
|
with open_table_ro(image.name()) as casa_table:
|
|
182
188
|
# the actual mask is a data var and data var names are all caps by convention
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
189
|
+
import re
|
|
190
|
+
|
|
191
|
+
if defmask in casa_table.keywordnames():
|
|
192
|
+
am = casa_table.getkeyword(defmask).upper()
|
|
193
|
+
am = re.sub(r"\bMASK(\d+)\b", r"MASK_\1", am)
|
|
194
|
+
else:
|
|
195
|
+
am = None
|
|
196
|
+
attrs[_image_flag] = "FLAG_" + image_type.upper()
|
|
197
|
+
"""
|
|
188
198
|
attrs["description"] = None
|
|
189
|
-
#
|
|
199
|
+
# Store history as a dict (not xr.Dataset) for Xarray compatibility
|
|
190
200
|
if history:
|
|
191
201
|
htable = os.sep.join([os.path.abspath(image.name()), "logtable"])
|
|
192
202
|
if os.path.isdir(htable):
|
|
193
|
-
|
|
203
|
+
history_xds = read_generic_table(htable)
|
|
204
|
+
# Convert xr.Dataset to dict for serialization compatibility
|
|
205
|
+
attrs["history"] = history_xds.to_dict()
|
|
194
206
|
else:
|
|
195
207
|
logger.warning(
|
|
196
208
|
f"Unable to find history table {htable}. History will not be included"
|
|
@@ -205,13 +217,14 @@ def _add_sky_or_aperture(
|
|
|
205
217
|
img_full_path: str,
|
|
206
218
|
has_sph_dims: bool,
|
|
207
219
|
history: bool,
|
|
220
|
+
image_type: str = "SKY",
|
|
208
221
|
) -> xr.Dataset:
|
|
209
222
|
xda = xr.DataArray(ary, dims=dimorder).astype(ary.dtype)
|
|
210
223
|
with _open_image_ro(img_full_path) as casa_image:
|
|
211
|
-
xda.attrs = _casa_image_to_xds_image_attrs(casa_image, history)
|
|
224
|
+
xda.attrs = _casa_image_to_xds_image_attrs(casa_image, history, image_type)
|
|
212
225
|
# xds.attrs = attrs
|
|
213
|
-
name = "SKY" if has_sph_dims else "APERTURE"
|
|
214
|
-
xda = xda.rename(
|
|
226
|
+
# name = "SKY" if has_sph_dims else "APERTURE"
|
|
227
|
+
xda = xda.rename(image_type)
|
|
215
228
|
xds[xda.name] = xda
|
|
216
229
|
return xds
|
|
217
230
|
|
|
@@ -257,6 +270,8 @@ def _casa_image_to_xds_attrs(img_full_path: str) -> dict:
|
|
|
257
270
|
"""
|
|
258
271
|
with _open_image_ro(img_full_path) as casa_image:
|
|
259
272
|
meta_dict = casa_image.info()
|
|
273
|
+
# print("meta_dict:", meta_dict)
|
|
274
|
+
# print("***********")
|
|
260
275
|
coord_dict = copy.deepcopy(meta_dict["coordinates"])
|
|
261
276
|
attrs = {}
|
|
262
277
|
dir_key = None
|
|
@@ -272,31 +287,67 @@ def _casa_image_to_xds_attrs(img_full_path: str) -> dict:
|
|
|
272
287
|
raise RuntimeError("No direction reference frame found")
|
|
273
288
|
casa_system = coord_dir_dict[system]
|
|
274
289
|
ap_system, ap_equinox = _convert_direction_system(casa_system, "native")
|
|
275
|
-
dir_dict = {}
|
|
276
290
|
|
|
277
|
-
|
|
278
|
-
|
|
291
|
+
coordinate_system_info = {}
|
|
292
|
+
|
|
293
|
+
unit0 = u.Unit(_get_unit(coord_dir_dict["units"][0]))
|
|
294
|
+
unit1 = u.Unit(_get_unit(coord_dir_dict["units"][1]))
|
|
295
|
+
ra = float((coord_dir_dict["crval"][0] * unit0).to("rad").value)
|
|
296
|
+
dec = float((coord_dir_dict["crval"][1] * unit1).to("rad").value)
|
|
297
|
+
coordinate_system_info["reference_direction"] = make_skycoord_dict(
|
|
298
|
+
data=[ra, dec], units="rad", frame=ap_system
|
|
279
299
|
)
|
|
280
300
|
if ap_equinox:
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
301
|
+
coordinate_system_info["reference_direction"]["attrs"][
|
|
302
|
+
"equinox"
|
|
303
|
+
] = ap_equinox
|
|
304
|
+
|
|
305
|
+
pol_dir = [-1, coord_dir_dict["latpole"] * _deg_to_rad]
|
|
306
|
+
if "lonpole" in coord_dir_dict:
|
|
307
|
+
pol_dir[0] = coord_dir_dict["lonpole"] * _deg_to_rad
|
|
308
|
+
else:
|
|
309
|
+
pol_dir[0] = coord_dir_dict["longpole"] * _deg_to_rad
|
|
310
|
+
|
|
311
|
+
coordinate_system_info["native_pole_direction"] = make_direction_location_dict(
|
|
312
|
+
pol_dir, "rad", "native_projection"
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
coordinate_system_info["projection"] = coord_dir_dict["projection"]
|
|
316
|
+
coordinate_system_info["projection_parameters"] = to_python_type(
|
|
317
|
+
coord_dir_dict["projection_parameters"]
|
|
318
|
+
)
|
|
319
|
+
coordinate_system_info["pixel_coordinate_transformation_matrix"] = (
|
|
320
|
+
to_python_type(coord_dir_dict["pc"])
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
attrs["coordinate_system_info"] = coordinate_system_info
|
|
298
324
|
return copy.deepcopy(attrs)
|
|
299
325
|
|
|
326
|
+
# dir_dict = {}
|
|
327
|
+
|
|
328
|
+
# dir_dict["reference"] = make_skycoord_dict(
|
|
329
|
+
# data=[0.0, 0.0], units="rad", frame=ap_system
|
|
330
|
+
# )
|
|
331
|
+
# if ap_equinox:
|
|
332
|
+
# dir_dict["reference"]["attrs"]["equinox"] = ap_equinox
|
|
333
|
+
# for i in range(2):
|
|
334
|
+
# unit = u.Unit(_get_unit(coord_dir_dict["units"][i]))
|
|
335
|
+
# q = coord_dir_dict["crval"][i] * unit
|
|
336
|
+
# x = q.to("rad")
|
|
337
|
+
# dir_dict["reference"]["data"][i] = float(x.value)
|
|
338
|
+
# k = "latpole"
|
|
339
|
+
# if k in coord_dir_dict:
|
|
340
|
+
# for j in (k, "lonpole"):
|
|
341
|
+
# m = "longpole" if j == "lonpole" else j
|
|
342
|
+
# dir_dict[j] = make_quantity(
|
|
343
|
+
# value=coord_dir_dict[m] * _deg_to_rad, units="rad", dims=["l", "m"]
|
|
344
|
+
# )
|
|
345
|
+
# for j in ("pc", "projection_parameters", "projection"):
|
|
346
|
+
# if j in coord_dir_dict:
|
|
347
|
+
# dir_dict[j] = coord_dir_dict[j]
|
|
348
|
+
# attrs["direction"] = dir_dict
|
|
349
|
+
# return copy.deepcopy(attrs)
|
|
350
|
+
|
|
300
351
|
|
|
301
352
|
def _casa_image_to_xds_coords(
|
|
302
353
|
img_full_path: str, verbose: bool, do_sky_coords: bool
|
|
@@ -330,14 +381,12 @@ def _casa_image_to_xds_coords(
|
|
|
330
381
|
attrs["sphr_dims"] = sphr_dims
|
|
331
382
|
coords = {}
|
|
332
383
|
coord_attrs = {}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
)
|
|
337
|
-
(velocity_vals, coord_attrs["velocity"]) = _get_velocity_values_attrs(
|
|
384
|
+
coords["time"], coord_attrs["time"] = _get_time_values_attrs(coord_dict)
|
|
385
|
+
coords["frequency"], coord_attrs["frequency"] = _get_freq_values_attrs(csys, shape)
|
|
386
|
+
velocity_vals, coord_attrs["velocity"] = _get_velocity_values_attrs(
|
|
338
387
|
coord_dict, coords["frequency"]
|
|
339
388
|
)
|
|
340
|
-
|
|
389
|
+
coords["polarization"], coord_attrs["polarization"] = _get_pol_values_attrs(
|
|
341
390
|
coord_dict
|
|
342
391
|
)
|
|
343
392
|
coords["velocity"] = (["frequency"], velocity_vals)
|
|
@@ -380,7 +429,7 @@ def _casa_image_to_xds_coords(
|
|
|
380
429
|
ret = _get_uv_values_attrs(coord_dict, axis_names, shape)
|
|
381
430
|
for z in ["u", "v"]:
|
|
382
431
|
coords[z], coord_attrs[z] = ret[z]
|
|
383
|
-
coords["
|
|
432
|
+
coords["beam_params_label"] = ["major", "minor", "pa"]
|
|
384
433
|
attrs["shape"] = shape
|
|
385
434
|
xds = xr.Dataset(coords=coords)
|
|
386
435
|
for c in coord_attrs.keys():
|
|
@@ -390,7 +439,7 @@ def _casa_image_to_xds_coords(
|
|
|
390
439
|
|
|
391
440
|
|
|
392
441
|
def _convert_direction_system(
|
|
393
|
-
casa_system: str, which: str, verbose: bool =
|
|
442
|
+
casa_system: str, which: str, verbose: bool = False
|
|
394
443
|
) -> tuple:
|
|
395
444
|
if casa_system == "J2000":
|
|
396
445
|
if verbose:
|
|
@@ -634,6 +683,7 @@ def _get_persistent_block(
|
|
|
634
683
|
block = _read_image_chunk(infile, shapes, starts)
|
|
635
684
|
block = np.expand_dims(block, new_axes)
|
|
636
685
|
block = block.transpose(transpose_list)
|
|
686
|
+
block = da.from_array(block, chunks=block.shape)
|
|
637
687
|
block = xr.DataArray(block, dims=dimorder)
|
|
638
688
|
return block
|
|
639
689
|
|
|
@@ -686,11 +736,11 @@ def _get_starts_shapes_slices(
|
|
|
686
736
|
def _get_time_values_attrs(cimage_coord_dict: dict) -> Tuple[List[float], dict]:
|
|
687
737
|
attrs = {}
|
|
688
738
|
attrs["type"] = "time"
|
|
689
|
-
attrs["scale"] = cimage_coord_dict["obsdate"]["refer"]
|
|
739
|
+
attrs["scale"] = cimage_coord_dict["obsdate"]["refer"].lower()
|
|
690
740
|
unit = cimage_coord_dict["obsdate"]["m0"]["unit"]
|
|
691
741
|
attrs["units"] = unit
|
|
692
742
|
time_val = cimage_coord_dict["obsdate"]["m0"]["value"]
|
|
693
|
-
attrs["format"] = _get_time_format(time_val, unit)
|
|
743
|
+
attrs["format"] = _get_time_format(time_val, unit).lower()
|
|
694
744
|
return ([time_val], copy.deepcopy(attrs))
|
|
695
745
|
|
|
696
746
|
|
|
@@ -829,7 +879,11 @@ def _get_velocity_values_attrs(
|
|
|
829
879
|
|
|
830
880
|
|
|
831
881
|
def _get_beam(
|
|
832
|
-
img_full_path: str,
|
|
882
|
+
img_full_path: str,
|
|
883
|
+
nchan: int,
|
|
884
|
+
npol: int,
|
|
885
|
+
as_dask_array: bool,
|
|
886
|
+
image_type: str = "SKY",
|
|
833
887
|
) -> Union[xr.DataArray, None]:
|
|
834
888
|
# the image may have multiple beams
|
|
835
889
|
with _open_image_ro(img_full_path) as casa_image:
|
|
@@ -862,10 +916,10 @@ def _get_beam(
|
|
|
862
916
|
if as_dask_array:
|
|
863
917
|
beam_array = da.array(beam_array)
|
|
864
918
|
xdb = xr.DataArray(
|
|
865
|
-
beam_array, dims=["time", "frequency", "polarization", "
|
|
919
|
+
beam_array, dims=["time", "frequency", "polarization", "beam_params_label"]
|
|
866
920
|
)
|
|
867
|
-
xdb = xdb.rename("
|
|
868
|
-
xdb = xdb.assign_coords(
|
|
921
|
+
xdb = xdb.rename("BEAM_FIT_PARAMS_" + image_type.upper())
|
|
922
|
+
xdb = xdb.assign_coords(beam_params_label=["major", "minor", "pa"])
|
|
869
923
|
xdb.attrs["units"] = "rad"
|
|
870
924
|
return xdb
|
|
871
925
|
|
|
@@ -1054,7 +1108,7 @@ def _read_image_array(
|
|
|
1054
1108
|
indicating the length of a chunk on that particular axis. If
|
|
1055
1109
|
a key is missing, the associated chunk length along that axis
|
|
1056
1110
|
is 1. 'l' represents the longitude like dimension, and 'm'
|
|
1057
|
-
represents the latitude like dimension. For
|
|
1111
|
+
represents the latitude like dimension. For aperture images,
|
|
1058
1112
|
'u' may be used in place of 'l', and 'v' in place of 'm'.
|
|
1059
1113
|
:type chunks: list | dict, required
|
|
1060
1114
|
:param mask: If specified, this is the associated image mask to read, rather than the actual
|