xradio 0.0.51__tar.gz → 0.0.52__tar.gz
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-0.0.51/src/xradio.egg-info → xradio-0.0.52}/PKG-INFO +4 -4
- {xradio-0.0.51 → xradio-0.0.52}/README.md +4 -4
- {xradio-0.0.51 → xradio-0.0.52}/pyproject.toml +1 -1
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/_utils/dict_helpers.py +24 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/image/_util/_casacore/xds_from_casacore.py +116 -69
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/image/_util/_casacore/xds_to_casacore.py +51 -32
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/image/_util/_fits/xds_from_fits.py +43 -52
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/image/_util/_zarr/common.py +1 -1
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/image/_util/_zarr/xds_from_zarr.py +37 -20
- xradio-0.0.52/src/xradio/image/_util/_zarr/xds_to_zarr.py +48 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/image/_util/casacore.py +6 -3
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_msv2/create_field_and_source_xds.py +9 -2
- {xradio-0.0.51 → xradio-0.0.52/src/xradio.egg-info}/PKG-INFO +4 -4
- xradio-0.0.51/src/xradio/image/_util/_zarr/xds_to_zarr.py +0 -49
- {xradio-0.0.51 → xradio-0.0.52}/LICENSE.txt +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/MANIFEST.in +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/setup.cfg +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/__init__.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/_utils/__init__.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/_utils/_casacore/tables.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/_utils/coord_math.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/_utils/list_and_array.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/_utils/schema.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/_utils/zarr/__init__.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/_utils/zarr/common.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/image/__init__.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/image/_util/__init__.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/image/_util/_casacore/__init__.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/image/_util/_casacore/common.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/image/_util/_zarr/zarr_low_level.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/image/_util/common.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/image/_util/fits.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/image/_util/image_factory.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/image/_util/zarr.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/image/image.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/__init__.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/__init__.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_msv2/_tables/load.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_msv2/_tables/load_main_table.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_msv2/_tables/read.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_msv2/_tables/read_main_table.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_msv2/_tables/read_subtables.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_msv2/_tables/table_query.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_msv2/_tables/write.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_msv2/_tables/write_exp_api.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_msv2/chunks.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_msv2/conversion.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_msv2/create_antenna_xds.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_msv2/descr.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_msv2/msv2_msv3.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_msv2/msv2_to_msv4_meta.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_msv2/msv4_info_dicts.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_msv2/msv4_sub_xdss.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_msv2/optimised_functions.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_msv2/partition_queries.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_msv2/partitions.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_msv2/subtables.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_utils/cds.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_utils/partition_attrs.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_utils/stokes_types.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_utils/xds_helper.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_zarr/encoding.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_zarr/read.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_zarr/write.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/msv2.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/zarr.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/convert_msv2_to_processing_set.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/load_processing_set.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/measurement_set_xdt.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/open_processing_set.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/processing_set_xdt.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/schema.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/schema/__init__.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/schema/bases.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/schema/check.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/schema/dataclass.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/schema/metamodel.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/schema/typing.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/sphinx/__init__.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio/sphinx/schema_table.py +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio.egg-info/SOURCES.txt +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio.egg-info/dependency_links.txt +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio.egg-info/requires.txt +0 -0
- {xradio-0.0.51 → xradio-0.0.52}/src/xradio.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: xradio
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.52
|
|
4
4
|
Summary: Xarray Radio Astronomy Data IO
|
|
5
5
|
Author-email: Jan-Willem Steeb <jsteeb@nrao.edu>, Federico Montesino Pouzols <pouzols@eso.edu>, Dave Mehringer <dmehring@nrao.edu>, Peter Wortmann <peter.wortmann@skao.int>
|
|
6
6
|
License: BSD 3-Clause License
|
|
@@ -80,9 +80,9 @@ Dynamic: license-file
|
|
|
80
80
|
Xarray Radio Astronomy Data IO is still in development.
|
|
81
81
|
|
|
82
82
|
[](https://www.python.org/downloads/release/python-3130/)
|
|
83
|
-

|
|
84
|
-

|
|
85
|
-

|
|
83
|
+
[](https://github.com/casangi/xradio/actions/workflows/python-testing-linux.yml?query=branch%3Amain)
|
|
84
|
+
[](https://github.com/casangi/xradio/actions/workflows/python-testing-macos.yml?query=branch%3Amain)
|
|
85
|
+
[](https://github.com/casangi/xradio/actions/workflows/run-ipynb.yml?query=branch%3Amain)
|
|
86
86
|
[](https://codecov.io/gh/casangi/xradio/branch/main/xradio)
|
|
87
87
|
[](https://xradio.readthedocs.io)
|
|
88
88
|
[](https://pypi.python.org/pypi/xradio/)
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
Xarray Radio Astronomy Data IO is still in development.
|
|
3
3
|
|
|
4
4
|
[](https://www.python.org/downloads/release/python-3130/)
|
|
5
|
-

|
|
6
|
-

|
|
7
|
-

|
|
5
|
+
[](https://github.com/casangi/xradio/actions/workflows/python-testing-linux.yml?query=branch%3Amain)
|
|
6
|
+
[](https://github.com/casangi/xradio/actions/workflows/python-testing-macos.yml?query=branch%3Amain)
|
|
7
|
+
[](https://github.com/casangi/xradio/actions/workflows/run-ipynb.yml?query=branch%3Amain)
|
|
8
8
|
[](https://codecov.io/gh/casangi/xradio/branch/main/xradio)
|
|
9
9
|
[](https://xradio.readthedocs.io)
|
|
10
10
|
[](https://pypi.python.org/pypi/xradio/)
|
|
@@ -24,4 +24,4 @@ pip install xradio
|
|
|
24
24
|
This will also install the minimal dependencies for XRADIO. To install the minimal dependencies and the interactive components (JupyterLab) use:
|
|
25
25
|
```sh
|
|
26
26
|
pip install "xradio[interactive]"
|
|
27
|
-
```
|
|
27
|
+
```
|
|
@@ -43,6 +43,30 @@ def make_time_measure_attrs(units=["s"], scale="utc", time_format="mjd") -> dict
|
|
|
43
43
|
return {"units": u, "scale": scale, "format": time_format, "type": "time"}
|
|
44
44
|
|
|
45
45
|
|
|
46
|
+
def make_time_measure_dict(data, units=["s"], scale="utc", time_format="mjd") -> dict:
|
|
47
|
+
"""
|
|
48
|
+
create a time measure dictionary given value and units
|
|
49
|
+
Parameters
|
|
50
|
+
----------
|
|
51
|
+
value : numeric or array of numerics
|
|
52
|
+
Time value
|
|
53
|
+
units: str
|
|
54
|
+
Time units
|
|
55
|
+
scale: str
|
|
56
|
+
Time scale
|
|
57
|
+
time_format: str
|
|
58
|
+
Time format
|
|
59
|
+
Returns
|
|
60
|
+
-------
|
|
61
|
+
dict
|
|
62
|
+
"""
|
|
63
|
+
x = {}
|
|
64
|
+
x["attrs"] = make_time_measure_attrs(units, scale, time_format)
|
|
65
|
+
x["data"] = data
|
|
66
|
+
x["dims"] = []
|
|
67
|
+
return x
|
|
68
|
+
|
|
69
|
+
|
|
46
70
|
def make_time_coord_attrs(units=["s"], scale="utc", time_format="mjd") -> dict:
|
|
47
71
|
"""
|
|
48
72
|
create a time measure dictionary given value and units
|
|
@@ -10,7 +10,7 @@ import numpy as np
|
|
|
10
10
|
import xarray as xr
|
|
11
11
|
from astropy import units as u
|
|
12
12
|
from casacore import tables
|
|
13
|
-
from casacore.images import coordinates
|
|
13
|
+
from casacore.images import coordinates, image as casa_image
|
|
14
14
|
|
|
15
15
|
from .common import (
|
|
16
16
|
_active_mask,
|
|
@@ -32,10 +32,11 @@ from ..common import (
|
|
|
32
32
|
from ...._utils._casacore.tables import extract_table_attributes, open_table_ro
|
|
33
33
|
from xradio._utils.coord_math import _deg_to_rad
|
|
34
34
|
from xradio._utils.dict_helpers import (
|
|
35
|
-
|
|
35
|
+
_casacore_q_to_xradio_q,
|
|
36
36
|
make_frequency_reference_dict,
|
|
37
|
+
make_quantity,
|
|
37
38
|
make_skycoord_dict,
|
|
38
|
-
|
|
39
|
+
make_time_measure_dict,
|
|
39
40
|
)
|
|
40
41
|
|
|
41
42
|
|
|
@@ -89,19 +90,126 @@ def _add_mask(
|
|
|
89
90
|
return xds
|
|
90
91
|
|
|
91
92
|
|
|
93
|
+
def _casa_image_to_xds_image_attrs(image: casa_image, history: bool = True) -> dict:
|
|
94
|
+
"""
|
|
95
|
+
get the image attributes from the casacoreimage object
|
|
96
|
+
"""
|
|
97
|
+
meta_dict = image.info()
|
|
98
|
+
coord_dict = copy.deepcopy(meta_dict["coordinates"])
|
|
99
|
+
attrs = {}
|
|
100
|
+
attrs[_image_type] = image.info()["imageinfo"]["imagetype"]
|
|
101
|
+
attrs["units"] = image.unit()
|
|
102
|
+
attrs["telescope"] = {}
|
|
103
|
+
telescope = attrs["telescope"]
|
|
104
|
+
for k in ("observer", "obsdate", "telescope", "telescopeposition"):
|
|
105
|
+
if k.startswith("telescope"):
|
|
106
|
+
if k == "telescope":
|
|
107
|
+
telescope["name"] = coord_dict[k]
|
|
108
|
+
elif k in coord_dict:
|
|
109
|
+
casa_pos = coord_dict[k]
|
|
110
|
+
location = {}
|
|
111
|
+
loc_attrs = {}
|
|
112
|
+
loc_attrs["type"] = "location"
|
|
113
|
+
loc_attrs["frame"] = casa_pos["refer"]
|
|
114
|
+
"""
|
|
115
|
+
if casa_pos["refer"] == "ITRF":
|
|
116
|
+
loc_attrs["ellipsoid"] = "GRS80"
|
|
117
|
+
"""
|
|
118
|
+
loc_attrs["units"] = [
|
|
119
|
+
casa_pos["m0"]["unit"],
|
|
120
|
+
casa_pos["m1"]["unit"],
|
|
121
|
+
casa_pos["m2"]["unit"],
|
|
122
|
+
]
|
|
123
|
+
loc_attrs["coordinate_system"] = "geocentric"
|
|
124
|
+
loc_attrs["origin_object_name"] = "earth"
|
|
125
|
+
location["attrs"] = loc_attrs
|
|
126
|
+
location["data"] = [
|
|
127
|
+
casa_pos["m0"]["value"],
|
|
128
|
+
casa_pos["m1"]["value"],
|
|
129
|
+
casa_pos["m2"]["value"],
|
|
130
|
+
]
|
|
131
|
+
telescope["location"] = location
|
|
132
|
+
"""
|
|
133
|
+
del (
|
|
134
|
+
telescope["position"]["refer"],
|
|
135
|
+
telescope["position"]["m0"],
|
|
136
|
+
telescope["position"]["m1"],
|
|
137
|
+
telescope["position"]["m2"],
|
|
138
|
+
)
|
|
139
|
+
"""
|
|
140
|
+
elif k == "obsdate":
|
|
141
|
+
obsdate = coord_dict[k]
|
|
142
|
+
"""
|
|
143
|
+
o_attrs = {"type": "time"}
|
|
144
|
+
o_attrs["scale"] = coord_dict[k]["refer"]
|
|
145
|
+
myu = coord_dict[k]["m0"]["unit"]
|
|
146
|
+
o_attrs["units"] = myu if isinstance(myu, list) else [myu]
|
|
147
|
+
o_attrs["format"] = _get_time_format(m0["value"], m0["unit"])
|
|
148
|
+
o_date = {}
|
|
149
|
+
o_date["attrs"] = o_attrs
|
|
150
|
+
"""
|
|
151
|
+
m0 = obsdate["m0"]
|
|
152
|
+
attrs["obsdate"] = make_time_measure_dict(
|
|
153
|
+
data=m0["value"],
|
|
154
|
+
units=m0["unit"],
|
|
155
|
+
scale=obsdate["refer"],
|
|
156
|
+
time_format=_get_time_format(m0["value"], m0["unit"]),
|
|
157
|
+
)
|
|
158
|
+
else:
|
|
159
|
+
attrs[k] = coord_dict[k] if k in coord_dict else ""
|
|
160
|
+
dir_key = next((k for k in coord_dict if k.startswith("direction")), None)
|
|
161
|
+
if dir_key:
|
|
162
|
+
frame, eqnx = _convert_direction_system(coord_dict[dir_key]["system"], "system")
|
|
163
|
+
else:
|
|
164
|
+
frame = "icrs"
|
|
165
|
+
logger.warning(
|
|
166
|
+
"No direction coordinate found from which "
|
|
167
|
+
"to get pointing center frame. Assuming ICRS"
|
|
168
|
+
)
|
|
169
|
+
# it looks like the pointing center is always in radians in a casa image coord system dict
|
|
170
|
+
# note that in a casa image, the pointing center does not explicitly have a reference frame
|
|
171
|
+
# associated with it.
|
|
172
|
+
# point_center = coord_dict["pointingcenter"]
|
|
173
|
+
attrs[_pointing_center] = make_skycoord_dict(
|
|
174
|
+
coord_dict["pointingcenter"]["value"].tolist(), ["rad", "rad"], frame
|
|
175
|
+
)
|
|
176
|
+
imageinfo = meta_dict["imageinfo"]
|
|
177
|
+
obj = "objectname"
|
|
178
|
+
attrs[_object_name] = imageinfo[obj] if obj in imageinfo else ""
|
|
179
|
+
attrs["user"] = meta_dict["miscinfo"]
|
|
180
|
+
defmask = "Image_defaultmask"
|
|
181
|
+
with open_table_ro(image.name()) as casa_table:
|
|
182
|
+
# the actual mask is a data var and data var names are all caps by convention
|
|
183
|
+
attrs[_active_mask] = (
|
|
184
|
+
casa_table.getkeyword(defmask).upper()
|
|
185
|
+
if defmask in casa_table.keywordnames()
|
|
186
|
+
else None
|
|
187
|
+
)
|
|
188
|
+
attrs["description"] = None
|
|
189
|
+
# if also loading history, put it as another xds in the image attrs
|
|
190
|
+
if history:
|
|
191
|
+
htable = os.sep.join([os.path.abspath(image.name()), "logtable"])
|
|
192
|
+
if os.path.isdir(htable):
|
|
193
|
+
attrs["history"] = read_generic_table(htable)
|
|
194
|
+
else:
|
|
195
|
+
logger.warning(
|
|
196
|
+
f"Unable to find history table {htable}. History will not be included"
|
|
197
|
+
)
|
|
198
|
+
return attrs
|
|
199
|
+
|
|
200
|
+
|
|
92
201
|
def _add_sky_or_aperture(
|
|
93
202
|
xds: xr.Dataset,
|
|
94
203
|
ary: Union[np.ndarray, da.array],
|
|
95
204
|
dimorder: list,
|
|
96
205
|
img_full_path: str,
|
|
97
206
|
has_sph_dims: bool,
|
|
207
|
+
history: bool,
|
|
98
208
|
) -> xr.Dataset:
|
|
99
209
|
xda = xr.DataArray(ary, dims=dimorder).astype(ary.dtype)
|
|
100
210
|
with _open_image_ro(img_full_path) as casa_image:
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
xda.attrs[_image_type] = image_type
|
|
104
|
-
xda.attrs["units"] = unit
|
|
211
|
+
xda.attrs = _casa_image_to_xds_image_attrs(casa_image, history)
|
|
212
|
+
# xds.attrs = attrs
|
|
105
213
|
name = "SKY" if has_sph_dims else "APERTURE"
|
|
106
214
|
xda = xda.rename(name)
|
|
107
215
|
xds[xda.name] = xda
|
|
@@ -143,7 +251,7 @@ def _add_vel_attrs(xds: xr.Dataset, coord_dict: dict) -> xr.Dataset:
|
|
|
143
251
|
return xds
|
|
144
252
|
|
|
145
253
|
|
|
146
|
-
def _casa_image_to_xds_attrs(img_full_path: str
|
|
254
|
+
def _casa_image_to_xds_attrs(img_full_path: str) -> dict:
|
|
147
255
|
"""
|
|
148
256
|
Get the xds level attribut/es as a python dictionary
|
|
149
257
|
"""
|
|
@@ -187,67 +295,6 @@ def _casa_image_to_xds_attrs(img_full_path: str, history: bool = True) -> dict:
|
|
|
187
295
|
if j in coord_dir_dict:
|
|
188
296
|
dir_dict[j] = coord_dir_dict[j]
|
|
189
297
|
attrs["direction"] = dir_dict
|
|
190
|
-
attrs["telescope"] = {}
|
|
191
|
-
telescope = attrs["telescope"]
|
|
192
|
-
attrs["obsdate"] = {"type": "time"}
|
|
193
|
-
obsdate = attrs["obsdate"]
|
|
194
|
-
attrs[_pointing_center] = coord_dict["pointingcenter"].copy()
|
|
195
|
-
for k in ("observer", "obsdate", "telescope", "telescopeposition"):
|
|
196
|
-
if k.startswith("telescope"):
|
|
197
|
-
if k == "telescope":
|
|
198
|
-
telescope["name"] = coord_dict[k]
|
|
199
|
-
elif k in coord_dict:
|
|
200
|
-
telescope["position"] = coord_dict[k]
|
|
201
|
-
telescope["position"]["ellipsoid"] = telescope["position"]["refer"]
|
|
202
|
-
if telescope["position"]["refer"] == "ITRF":
|
|
203
|
-
telescope["position"]["ellipsoid"] = "GRS80"
|
|
204
|
-
telescope["position"]["units"] = [
|
|
205
|
-
telescope["position"]["m0"]["unit"],
|
|
206
|
-
telescope["position"]["m1"]["unit"],
|
|
207
|
-
telescope["position"]["m2"]["unit"],
|
|
208
|
-
]
|
|
209
|
-
telescope["position"]["value"] = [
|
|
210
|
-
telescope["position"]["m0"]["value"],
|
|
211
|
-
telescope["position"]["m1"]["value"],
|
|
212
|
-
telescope["position"]["m2"]["value"],
|
|
213
|
-
]
|
|
214
|
-
del (
|
|
215
|
-
telescope["position"]["refer"],
|
|
216
|
-
telescope["position"]["m0"],
|
|
217
|
-
telescope["position"]["m1"],
|
|
218
|
-
telescope["position"]["m2"],
|
|
219
|
-
)
|
|
220
|
-
elif k == "obsdate":
|
|
221
|
-
obsdate["scale"] = coord_dict[k]["refer"]
|
|
222
|
-
myu = coord_dict[k]["m0"]["unit"]
|
|
223
|
-
obsdate["units"] = myu if isinstance(myu, list) else [myu]
|
|
224
|
-
obsdate["value"] = coord_dict[k]["m0"]["value"]
|
|
225
|
-
obsdate["format"] = _get_time_format(obsdate["value"], obsdate["units"])
|
|
226
|
-
obsdate["type"] = "time"
|
|
227
|
-
else:
|
|
228
|
-
attrs[k] = coord_dict[k] if k in coord_dict else ""
|
|
229
|
-
imageinfo = meta_dict["imageinfo"]
|
|
230
|
-
obj = "objectname"
|
|
231
|
-
attrs[_object_name] = imageinfo[obj] if obj in imageinfo else ""
|
|
232
|
-
attrs["user"] = meta_dict["miscinfo"]
|
|
233
|
-
defmask = "Image_defaultmask"
|
|
234
|
-
with open_table_ro(img_full_path) as casa_table:
|
|
235
|
-
# the actual mask is a data var and data var names are all caps by convention
|
|
236
|
-
attrs[_active_mask] = (
|
|
237
|
-
casa_table.getkeyword(defmask).upper()
|
|
238
|
-
if defmask in casa_table.keywordnames()
|
|
239
|
-
else None
|
|
240
|
-
)
|
|
241
|
-
attrs["description"] = None
|
|
242
|
-
# if also loading history, put it as another xds in the attrs
|
|
243
|
-
if history:
|
|
244
|
-
htable = os.sep.join([img_full_path, "logtable"])
|
|
245
|
-
if os.path.isdir(htable):
|
|
246
|
-
attrs["history"] = read_generic_table(htable)
|
|
247
|
-
else:
|
|
248
|
-
logger.warning(
|
|
249
|
-
f"Unable to find history table {htable}. History will not be included"
|
|
250
|
-
)
|
|
251
298
|
return copy.deepcopy(attrs)
|
|
252
299
|
|
|
253
300
|
|
|
@@ -19,12 +19,16 @@ def _compute_direction_dict(xds: xr.Dataset) -> dict:
|
|
|
19
19
|
"""
|
|
20
20
|
direction = {}
|
|
21
21
|
xds_dir = xds.attrs["direction"]
|
|
22
|
+
direction["_axes_sizes"] = np.array(
|
|
23
|
+
[xds.sizes[dim] for dim in ("l", "m")], dtype=np.int32
|
|
24
|
+
)
|
|
25
|
+
direction["_image_axes"] = np.array([2, 3], dtype=np.int32)
|
|
22
26
|
direction["system"] = xds_dir["reference"]["attrs"]["equinox"].upper()
|
|
23
27
|
if direction["system"] == "J2000.0":
|
|
24
28
|
direction["system"] = "J2000"
|
|
25
29
|
direction["projection"] = xds_dir["projection"]
|
|
26
30
|
direction["projection_parameters"] = xds_dir["projection_parameters"]
|
|
27
|
-
direction["units"] =
|
|
31
|
+
direction["units"] = xds_dir["reference"]["attrs"]["units"]
|
|
28
32
|
direction["crval"] = np.array(xds_dir["reference"]["data"])
|
|
29
33
|
direction["cdelt"] = np.array((xds.l[1] - xds.l[0], xds.m[1] - xds.m[0]))
|
|
30
34
|
direction["crpix"] = _compute_sky_reference_pixel(xds)
|
|
@@ -34,9 +38,9 @@ def _compute_direction_dict(xds: xr.Dataset) -> dict:
|
|
|
34
38
|
for s in ["longpole", "latpole"]:
|
|
35
39
|
m = "lonpole" if s == "longpole" else s
|
|
36
40
|
# lonpole, latpole are numerical values in degrees in casa images
|
|
37
|
-
direction[s] =
|
|
38
|
-
str(xds_dir[m]["data"]) + xds_dir[m]["attrs"]["units"][0]
|
|
39
|
-
)
|
|
41
|
+
direction[s] = float(
|
|
42
|
+
Angle(str(xds_dir[m]["data"]) + xds_dir[m]["attrs"]["units"][0]).deg
|
|
43
|
+
)
|
|
40
44
|
return direction
|
|
41
45
|
|
|
42
46
|
|
|
@@ -69,6 +73,8 @@ def _compute_spectral_dict(xds: xr.Dataset) -> dict:
|
|
|
69
73
|
for a CASA image coordinate system
|
|
70
74
|
"""
|
|
71
75
|
spec = {}
|
|
76
|
+
spec["_axes_sizes"] = np.array([xds.sizes["frequency"]], dtype=np.int32)
|
|
77
|
+
spec["_image_axes"] = np.array([0], dtype=np.int32)
|
|
72
78
|
spec["formatUnit"] = ""
|
|
73
79
|
spec["name"] = "Frequency"
|
|
74
80
|
# spec["nativeType"] = _native_types.index(xds.frequency.attrs["native_type"])
|
|
@@ -76,7 +82,7 @@ def _compute_spectral_dict(xds: xr.Dataset) -> dict:
|
|
|
76
82
|
spec["nativeType"] = 0
|
|
77
83
|
spec["restfreq"] = xds.frequency.attrs["rest_frequency"]["data"]
|
|
78
84
|
# spec["restfreqs"] = copy.deepcopy(xds.frequency.attrs["restfreqs"]["value"])
|
|
79
|
-
spec["restfreqs"] = [spec["restfreq"]]
|
|
85
|
+
spec["restfreqs"] = np.array([spec["restfreq"]])
|
|
80
86
|
spec["system"] = xds.frequency.attrs["reference_value"]["attrs"]["observer"].upper()
|
|
81
87
|
u = xds.frequency.attrs["reference_value"]["attrs"]["units"]
|
|
82
88
|
spec["unit"] = u if isinstance(u, str) else u[0]
|
|
@@ -88,53 +94,65 @@ def _compute_spectral_dict(xds: xr.Dataset) -> dict:
|
|
|
88
94
|
wcs = {}
|
|
89
95
|
wcs["ctype"] = "FREQ"
|
|
90
96
|
wcs["pc"] = 1.0
|
|
91
|
-
wcs["crval"] = xds.frequency.attrs["reference_value"]["data"]
|
|
92
|
-
wcs["cdelt"] = xds.frequency.values[1] - xds.frequency.values[0]
|
|
93
|
-
wcs["crpix"] = (wcs["crval"] - xds.frequency.values[0]) / wcs["cdelt"]
|
|
97
|
+
wcs["crval"] = float(xds.frequency.attrs["reference_value"]["data"])
|
|
98
|
+
wcs["cdelt"] = float(xds.frequency.values[1] - xds.frequency.values[0])
|
|
99
|
+
wcs["crpix"] = float((wcs["crval"] - xds.frequency.values[0]) / wcs["cdelt"])
|
|
94
100
|
spec["wcs"] = wcs
|
|
95
101
|
return spec
|
|
96
102
|
|
|
97
103
|
|
|
98
104
|
def _coord_dict_from_xds(xds: xr.Dataset) -> dict:
|
|
99
105
|
coord = {}
|
|
100
|
-
|
|
101
|
-
|
|
106
|
+
sky_ap = "SKY" if "SKY" in xds.data_vars else "APERTURE"
|
|
107
|
+
if "telescope" in xds[sky_ap].attrs:
|
|
108
|
+
tel = xds[sky_ap].attrs["telescope"]
|
|
109
|
+
if "name" in tel:
|
|
110
|
+
coord["telescope"] = xds[sky_ap].attrs["telescope"]["name"]
|
|
111
|
+
if "location" in tel:
|
|
112
|
+
xds_telloc = tel["location"]
|
|
113
|
+
telloc = {}
|
|
114
|
+
telloc["refer"] = xds_telloc["attrs"]["frame"]
|
|
115
|
+
if telloc["refer"] == "GRS80":
|
|
116
|
+
telloc["refer"] = "ITRF"
|
|
117
|
+
for i in range(3):
|
|
118
|
+
telloc[f"m{i}"] = {
|
|
119
|
+
"unit": xds_telloc["attrs"]["units"][i],
|
|
120
|
+
"value": xds_telloc["data"][i],
|
|
121
|
+
}
|
|
122
|
+
telloc["type"] = "position"
|
|
123
|
+
coord["telescopeposition"] = telloc
|
|
124
|
+
if "observer" in xds[sky_ap].attrs:
|
|
125
|
+
coord["observer"] = xds[sky_ap].attrs["observer"]
|
|
102
126
|
obsdate = {}
|
|
103
127
|
obsdate["refer"] = xds.coords["time"].attrs["scale"]
|
|
104
128
|
obsdate["type"] = "epoch"
|
|
105
129
|
obsdate["m0"] = {}
|
|
106
130
|
obsdate["m0"]["unit"] = xds.coords["time"].attrs["units"][0]
|
|
107
|
-
obsdate["m0"]["value"] = xds.coords["time"].values[0]
|
|
131
|
+
obsdate["m0"]["value"] = float(xds.coords["time"].values[0])
|
|
108
132
|
coord["obsdate"] = obsdate
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
telpos["refer"] = "ITRF"
|
|
115
|
-
for i in range(3):
|
|
116
|
-
telpos[f"m{i}"] = {
|
|
117
|
-
"unit": xds.attrs["telescope"]["position"]["units"][i],
|
|
118
|
-
"value": xds.attrs["telescope"]["position"]["value"][i],
|
|
119
|
-
}
|
|
120
|
-
telpos["type"] = "position"
|
|
121
|
-
coord["telescopeposition"] = telpos
|
|
133
|
+
if _pointing_center in xds[sky_ap].attrs:
|
|
134
|
+
coord["pointingcenter"] = {
|
|
135
|
+
"initial": True,
|
|
136
|
+
"value": xds[sky_ap].attrs[_pointing_center]["data"],
|
|
137
|
+
}
|
|
122
138
|
if "l" in xds.coords:
|
|
123
139
|
coord["direction0"] = _compute_direction_dict(xds)
|
|
124
140
|
else:
|
|
125
141
|
coord["linear0"] = _compute_linear_dict(xds)
|
|
126
142
|
coord["stokes1"] = {
|
|
127
|
-
"
|
|
143
|
+
"_axes_sizes": np.array([xds.sizes["polarization"]], dtype=np.int32),
|
|
144
|
+
"_image_axes": np.array([1], dtype=np.int32),
|
|
145
|
+
"axes": ["Stokes"],
|
|
128
146
|
"cdelt": np.array([1.0]),
|
|
129
147
|
"crpix": np.array([0.0]),
|
|
130
148
|
"crval": np.array([1.0]),
|
|
131
149
|
"pc": np.array([[1.0]]),
|
|
132
|
-
"stokes":
|
|
150
|
+
"stokes": xds.polarization.values.tolist(),
|
|
133
151
|
}
|
|
134
152
|
coord["spectral2"] = _compute_spectral_dict(xds)
|
|
135
|
-
coord["pixelmap0"] = np.array([0, 1])
|
|
136
|
-
coord["pixelmap1"] = np.array([2])
|
|
137
|
-
coord["pixelmap2"] = np.array([3])
|
|
153
|
+
coord["pixelmap0"] = np.array([0, 1], dtype=np.int32)
|
|
154
|
+
coord["pixelmap1"] = np.array([2], dtype=np.int32)
|
|
155
|
+
coord["pixelmap2"] = np.array([3], dtype=np.int32)
|
|
138
156
|
coord["pixelreplace0"] = np.array([0.0, 0.0])
|
|
139
157
|
coord["pixelreplace1"] = np.array([0.0])
|
|
140
158
|
coord["pixelreplace2"] = np.array([0.0])
|
|
@@ -144,7 +162,6 @@ def _coord_dict_from_xds(xds: xr.Dataset) -> dict:
|
|
|
144
162
|
# this probbably needs some verification
|
|
145
163
|
coord["worldreplace0"] = [0.0, 0.0]
|
|
146
164
|
coord["worldreplace1"] = np.array(coord["stokes1"]["crval"])
|
|
147
|
-
# print("spectral", coord["spectral2"])
|
|
148
165
|
coord["worldreplace2"] = np.array(coord["spectral2"]["wcs"]["crval"])
|
|
149
166
|
return coord
|
|
150
167
|
|
|
@@ -181,7 +198,7 @@ def _imageinfo_dict_from_xds(xds: xr.Dataset) -> dict:
|
|
|
181
198
|
ii["image_type"] = (
|
|
182
199
|
xds[ap_sky].attrs["image_type"] if "image_type" in xds[ap_sky].attrs else ""
|
|
183
200
|
)
|
|
184
|
-
ii["objectname"] = xds.attrs[_object_name]
|
|
201
|
+
ii["objectname"] = xds[ap_sky].attrs[_object_name]
|
|
185
202
|
if "BEAM" in xds.data_vars:
|
|
186
203
|
# multi beam
|
|
187
204
|
pp = {}
|
|
@@ -231,7 +248,9 @@ def _write_casa_data(xds: xr.Dataset, image_full_path: str) -> None:
|
|
|
231
248
|
else ("frequency", "polarization", "v", "u")
|
|
232
249
|
)
|
|
233
250
|
casa_image_shape = xds[sky_ap].isel(time=0).transpose(*trans_coords).shape[::-1]
|
|
234
|
-
active_mask =
|
|
251
|
+
active_mask = (
|
|
252
|
+
xds[sky_ap].attrs["active_mask"] if _active_mask in xds[sky_ap].attrs else ""
|
|
253
|
+
)
|
|
235
254
|
masks = []
|
|
236
255
|
masks_rec = {}
|
|
237
256
|
mask_rec = {
|
|
@@ -17,9 +17,10 @@ from ..common import (
|
|
|
17
17
|
)
|
|
18
18
|
from xradio._utils.coord_math import _deg_to_rad
|
|
19
19
|
from xradio._utils.dict_helpers import (
|
|
20
|
-
make_quantity,
|
|
21
20
|
make_frequency_reference_dict,
|
|
21
|
+
make_quantity,
|
|
22
22
|
make_skycoord_dict,
|
|
23
|
+
make_time_measure_dict,
|
|
23
24
|
)
|
|
24
25
|
import copy
|
|
25
26
|
import dask
|
|
@@ -49,7 +50,7 @@ def _fits_image_to_xds(
|
|
|
49
50
|
sphr_dims = helpers["sphr_dims"]
|
|
50
51
|
ary = _read_image_array(img_full_path, chunks, helpers, verbose)
|
|
51
52
|
dim_order = _get_xds_dim_order(sphr_dims)
|
|
52
|
-
xds = _add_sky_or_aperture(xds, ary, dim_order, helpers, sphr_dims)
|
|
53
|
+
xds = _add_sky_or_aperture(xds, ary, dim_order, header, helpers, sphr_dims)
|
|
53
54
|
xds.attrs = attrs
|
|
54
55
|
xds = _add_coord_attrs(xds, helpers)
|
|
55
56
|
if helpers["has_multibeam"]:
|
|
@@ -70,13 +71,7 @@ def _add_coord_attrs(xds: xr.Dataset, helpers: dict) -> xr.Dataset:
|
|
|
70
71
|
|
|
71
72
|
def _add_time_attrs(xds: xr.Dataset, helpers: dict) -> xr.Dataset:
|
|
72
73
|
time_coord = xds.coords["time"]
|
|
73
|
-
|
|
74
|
-
del meta["value"]
|
|
75
|
-
# meta["units"] = [ meta["units"] ]
|
|
76
|
-
# meta['format'] = 'MJD'
|
|
77
|
-
# meta['time_scale'] = meta['refer']
|
|
78
|
-
# del meta['refer']
|
|
79
|
-
time_coord.attrs = meta
|
|
74
|
+
time_coord.attrs = copy.deepcopy(helpers["obsdate"]["attrs"])
|
|
80
75
|
xds.assign_coords(time=time_coord)
|
|
81
76
|
return xds
|
|
82
77
|
|
|
@@ -176,15 +171,6 @@ def _xds_direction_attrs_from_header(helpers: dict, header) -> dict:
|
|
|
176
171
|
direction["reference"] = make_skycoord_dict(
|
|
177
172
|
[0.0, 0.0], units=["rad", "rad"], frame=ref_sys
|
|
178
173
|
)
|
|
179
|
-
"""
|
|
180
|
-
direction["reference"] = {
|
|
181
|
-
"type": "sky_coord",
|
|
182
|
-
"frame": ref_sys,
|
|
183
|
-
"equinox": ref_eqx,
|
|
184
|
-
"units": ["rad", "rad"],
|
|
185
|
-
"value": [0.0, 0.0],
|
|
186
|
-
}
|
|
187
|
-
"""
|
|
188
174
|
dir_axes = helpers["dir_axes"]
|
|
189
175
|
ddata = []
|
|
190
176
|
dunits = []
|
|
@@ -261,18 +247,21 @@ def _get_telescope_metadata(helpers: dict, header) -> dict:
|
|
|
261
247
|
r = np.sqrt(np.sum(xyz * xyz))
|
|
262
248
|
lat = np.arcsin(z / r)
|
|
263
249
|
long = np.arctan2(y, x)
|
|
264
|
-
tel["
|
|
265
|
-
"
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
250
|
+
tel["location"] = {
|
|
251
|
+
"attrs": {
|
|
252
|
+
"coordinate_system": "geocentric",
|
|
253
|
+
# I haven't seen a FITS keyword for reference frame of telescope posiiton
|
|
254
|
+
"frame": "ITRF",
|
|
255
|
+
"origin_object_name": "earth",
|
|
256
|
+
"type": "location",
|
|
257
|
+
"units": ["rad", "rad", "m"],
|
|
258
|
+
},
|
|
259
|
+
"data": np.array([long, lat, r]),
|
|
270
260
|
}
|
|
271
|
-
helpers["tel_pos"] = tel["position"]
|
|
272
261
|
return tel
|
|
273
262
|
|
|
274
263
|
|
|
275
|
-
def
|
|
264
|
+
def _compute_pointing_center(helpers: dict, header) -> dict:
|
|
276
265
|
# Neither helpers or header is modified
|
|
277
266
|
t_axes = helpers["t_axes"]
|
|
278
267
|
long_unit = header[f"CUNIT{t_axes[0]}"]
|
|
@@ -285,7 +274,9 @@ def _pointing_center_to_metadata(helpers: dict, header) -> dict:
|
|
|
285
274
|
pc_lat = float(header[f"CRVAL{t_axes[1]}"]) * unit[1]
|
|
286
275
|
pc_long = pc_long.to(u.rad).value
|
|
287
276
|
pc_lat = pc_lat.to(u.rad).value
|
|
288
|
-
return
|
|
277
|
+
return make_skycoord_dict(
|
|
278
|
+
[pc_long, pc_lat], units=["rad", "rad"], frame=helpers["ref_sys"]
|
|
279
|
+
)
|
|
289
280
|
|
|
290
281
|
|
|
291
282
|
def _user_attrs_from_header(header) -> dict:
|
|
@@ -382,7 +373,7 @@ def _create_dim_map(helpers: dict, header) -> dict:
|
|
|
382
373
|
return dim_map
|
|
383
374
|
|
|
384
375
|
|
|
385
|
-
def _fits_header_to_xds_attrs(hdulist: fits.hdu.hdulist.HDUList) ->
|
|
376
|
+
def _fits_header_to_xds_attrs(hdulist: fits.hdu.hdulist.HDUList) -> tuple:
|
|
386
377
|
primary = None
|
|
387
378
|
beams = None
|
|
388
379
|
for hdu in hdulist:
|
|
@@ -418,9 +409,7 @@ def _fits_header_to_xds_attrs(hdulist: fits.hdu.hdulist.HDUList) -> dict:
|
|
|
418
409
|
if dir_axes is not None:
|
|
419
410
|
attrs["direction"] = _xds_direction_attrs_from_header(helpers, header)
|
|
420
411
|
# FIXME read fits data in chunks in case all data too large to hold in memory
|
|
421
|
-
has_mask = da.any(da.isnan(primary.data)).compute()
|
|
422
|
-
attrs["active_mask"] = "MASK0" if has_mask else None
|
|
423
|
-
helpers["has_mask"] = has_mask
|
|
412
|
+
helpers["has_mask"] = da.any(da.isnan(primary.data)).compute()
|
|
424
413
|
beam = _beam_attr_from_header(helpers, header)
|
|
425
414
|
if beam != "mb":
|
|
426
415
|
helpers["beam"] = beam
|
|
@@ -432,24 +421,15 @@ def _fits_header_to_xds_attrs(hdulist: fits.hdu.hdulist.HDUList) -> dict:
|
|
|
432
421
|
helpers["dtype"] = "float64"
|
|
433
422
|
else:
|
|
434
423
|
raise RuntimeError(f'Unhandled data type {header["BITPIX"]}')
|
|
435
|
-
helpers["
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
obsdate["scale"] = header["TIMESYS"]
|
|
443
|
-
obsdate["format"] = "MJD"
|
|
444
|
-
attrs["obsdate"] = obsdate
|
|
445
|
-
helpers["obsdate"] = obsdate
|
|
446
|
-
attrs["observer"] = header["OBSERVER"]
|
|
447
|
-
attrs["pointing_center"] = _pointing_center_to_metadata(helpers, header)
|
|
448
|
-
attrs["description"] = None
|
|
449
|
-
attrs["telescope"] = _get_telescope_metadata(helpers, header)
|
|
424
|
+
helpers["obsdate"] = make_time_measure_dict(
|
|
425
|
+
data=Time(header["DATE-OBS"], format="isot").mjd,
|
|
426
|
+
units=["d"],
|
|
427
|
+
scale=header["TIMESYS"],
|
|
428
|
+
time_format="MJD",
|
|
429
|
+
)
|
|
430
|
+
|
|
450
431
|
# TODO complete _make_history_xds when spec has been finalized
|
|
451
432
|
# attrs['history'] = _make_history_xds(header)
|
|
452
|
-
attrs["user"] = _user_attrs_from_header(header)
|
|
453
433
|
return attrs, helpers, header
|
|
454
434
|
|
|
455
435
|
|
|
@@ -532,7 +512,7 @@ def _create_coords(
|
|
|
532
512
|
|
|
533
513
|
|
|
534
514
|
def _get_time_values(helpers):
|
|
535
|
-
return [helpers["obsdate"]["
|
|
515
|
+
return [helpers["obsdate"]["data"]]
|
|
536
516
|
|
|
537
517
|
|
|
538
518
|
def _get_pol_values(helpers):
|
|
@@ -710,14 +690,22 @@ def _add_sky_or_aperture(
|
|
|
710
690
|
xds: xr.Dataset,
|
|
711
691
|
ary: Union[np.ndarray, da.array],
|
|
712
692
|
dim_order: list,
|
|
693
|
+
header,
|
|
713
694
|
helpers: dict,
|
|
714
695
|
has_sph_dims: bool,
|
|
715
696
|
) -> xr.Dataset:
|
|
716
697
|
xda = xr.DataArray(ary, dims=dim_order)
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
698
|
+
for h, a in zip(
|
|
699
|
+
["BUNIT", "BTYPE", "OBJECT", "OBSERVER"],
|
|
700
|
+
["units", _image_type, "object_name", "observer"],
|
|
701
|
+
):
|
|
702
|
+
if h in header:
|
|
703
|
+
xda.attrs[a] = header[h]
|
|
704
|
+
xda.attrs["obsdate"] = helpers["obsdate"].copy()
|
|
705
|
+
xda.attrs["pointing_center"] = _compute_pointing_center(helpers, header)
|
|
706
|
+
xda.attrs["telescope"] = _get_telescope_metadata(helpers, header)
|
|
707
|
+
xda.attrs["description"] = None
|
|
708
|
+
xda.attrs["user"] = _user_attrs_from_header(header)
|
|
721
709
|
name = "SKY" if has_sph_dims else "APERTURE"
|
|
722
710
|
xda = xda.rename(name)
|
|
723
711
|
xds[xda.name] = xda
|
|
@@ -727,6 +715,9 @@ def _add_sky_or_aperture(
|
|
|
727
715
|
mask.attrs = {}
|
|
728
716
|
mask = mask.rename("MASK0")
|
|
729
717
|
xds["MASK0"] = mask
|
|
718
|
+
xda.attrs["active_mask"] = "MASK0"
|
|
719
|
+
xda = xda.rename(name)
|
|
720
|
+
xds[xda.name] = xda
|
|
730
721
|
return xds
|
|
731
722
|
|
|
732
723
|
|
|
@@ -12,9 +12,9 @@ from xradio._utils.zarr.common import _get_file_system_and_items
|
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
def _read_zarr(
|
|
15
|
-
zarr_store: str,
|
|
15
|
+
zarr_store: str, id_dict: dict, selection: dict = {}
|
|
16
16
|
) -> (xr.Dataset, bool):
|
|
17
|
-
# supported key/values in
|
|
17
|
+
# supported key/values in id_dict are:
|
|
18
18
|
# "dv"
|
|
19
19
|
# what data variables should be returned as.
|
|
20
20
|
# "numpy": numpy arrays
|
|
@@ -29,27 +29,27 @@ def _read_zarr(
|
|
|
29
29
|
do_dask = False
|
|
30
30
|
do_numpy = False
|
|
31
31
|
do_np_coords = False
|
|
32
|
-
if "dv" in
|
|
33
|
-
dv =
|
|
32
|
+
if "dv" in id_dict:
|
|
33
|
+
dv = id_dict["dv"]
|
|
34
34
|
if dv in ["dask", "numpy"]:
|
|
35
35
|
do_dask = dv == "dask"
|
|
36
36
|
do_numpy = not do_dask
|
|
37
37
|
else:
|
|
38
38
|
raise ValueError(
|
|
39
|
-
f"Unsupported value {
|
|
39
|
+
f"Unsupported value {id_dict[dv]} for id_dict[dv]. "
|
|
40
40
|
"Supported values are 'dask' and 'numpy'"
|
|
41
41
|
)
|
|
42
|
-
if "coords" in
|
|
43
|
-
c =
|
|
42
|
+
if "coords" in id_dict:
|
|
43
|
+
c = id_dict["coords"]
|
|
44
44
|
if c == "numpy":
|
|
45
45
|
do_np_coords = True
|
|
46
46
|
else:
|
|
47
47
|
raise ValueError(
|
|
48
|
-
f"Unexpected value {c} for
|
|
48
|
+
f"Unexpected value {c} for id_dict[coords]. "
|
|
49
49
|
"The supported value is 'numpy'"
|
|
50
50
|
)
|
|
51
51
|
# do not pass selection, because that is only for the top level data vars
|
|
52
|
-
xds = _decode(xds, zarr_store,
|
|
52
|
+
xds = _decode(xds, zarr_store, id_dict)
|
|
53
53
|
if do_np_coords:
|
|
54
54
|
xds = _coords_to_numpy(xds)
|
|
55
55
|
if do_dask:
|
|
@@ -59,11 +59,9 @@ def _read_zarr(
|
|
|
59
59
|
return xds
|
|
60
60
|
|
|
61
61
|
|
|
62
|
-
def _decode(xds: xr.Dataset, zarr_store: str,
|
|
62
|
+
def _decode(xds: xr.Dataset, zarr_store: str, id_dict: dict) -> xr.Dataset:
|
|
63
63
|
xds.attrs = _decode_dict(xds.attrs, "")
|
|
64
|
-
|
|
65
|
-
for k, v in sub_xdses.items():
|
|
66
|
-
xds.attrs[k] = v
|
|
64
|
+
_decode_sub_xdses(xds, zarr_store, id_dict)
|
|
67
65
|
return xds
|
|
68
66
|
|
|
69
67
|
|
|
@@ -85,26 +83,45 @@ def _decode_dict(my_dict: dict, top_key: str) -> dict:
|
|
|
85
83
|
return my_dict
|
|
86
84
|
|
|
87
85
|
|
|
88
|
-
def _decode_sub_xdses(
|
|
89
|
-
|
|
86
|
+
def _decode_sub_xdses(xarrayObj, top_dir: str, id_dict: dict) -> None:
|
|
87
|
+
# FIXME this also needs to support S3
|
|
88
|
+
# determine immediate subdirs of zarr_store
|
|
89
|
+
entries = os.scandir(top_dir)
|
|
90
|
+
for d in entries:
|
|
91
|
+
path = os.path.join(top_dir, d.name)
|
|
92
|
+
if os.path.isdir(path):
|
|
93
|
+
if d.name.startswith(_top_level_sub_xds):
|
|
94
|
+
ky = d.name[len(_top_level_sub_xds) :]
|
|
95
|
+
xarrayObj.attrs[ky] = _read_zarr(path, id_dict)
|
|
96
|
+
# TODO if attrs that are xdses have attrs that are xdses ...
|
|
97
|
+
else:
|
|
98
|
+
# descend into the directory
|
|
99
|
+
_decode_sub_xdses(xarrayObj[d.name], path, id_dict)
|
|
90
100
|
|
|
91
|
-
fs, store_contents = _get_file_system_and_items(zarr_store)
|
|
92
101
|
|
|
102
|
+
"""
|
|
103
|
+
def _decode_sub_xdses(zarr_store: str, id_dict: dict) -> dict:
|
|
104
|
+
sub_xdses = {}
|
|
105
|
+
fs, store_contents = _get_file_system_and_items(zarr_store)
|
|
93
106
|
if isinstance(fs, s3fs.core.S3FileSystem):
|
|
94
107
|
# could we just use the items as returned from the helper function..?
|
|
95
108
|
store_tree = fs.walk(zarr_store, topdown=True)
|
|
109
|
+
# Q: what is prepend_s3 used for? In this version it is defined but not used.
|
|
96
110
|
prepend_s3 = "s3://"
|
|
97
111
|
else:
|
|
98
112
|
store_tree = os.walk(zarr_store, topdown=True)
|
|
99
113
|
prepend_s3 = ""
|
|
100
|
-
|
|
101
114
|
for root, dirs, files in store_tree:
|
|
115
|
+
relpath = os.path.relpath(root, zarr_store)
|
|
116
|
+
print("rpath", relpath)
|
|
102
117
|
for d in dirs:
|
|
103
118
|
if d.startswith(_top_level_sub_xds):
|
|
104
|
-
xds = _read_zarr(os.sep.join([root, d]),
|
|
119
|
+
xds = _read_zarr(os.sep.join([root, d]), id_dict)
|
|
105
120
|
# for k, v in xds.data_vars.items():
|
|
106
121
|
# xds = xds.drop_vars([k]).assign({k: v.compute()})
|
|
107
|
-
ky = d[len(_top_level_sub_xds)
|
|
122
|
+
ky = d[len(_top_level_sub_xds) :]
|
|
108
123
|
sub_xdses[ky] = xds
|
|
109
|
-
|
|
124
|
+
print(f"Sub xdses: {sub_xdses.keys()}")
|
|
125
|
+
print("return")
|
|
110
126
|
return sub_xdses
|
|
127
|
+
"""
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import numpy as np
|
|
3
|
+
import xarray as xr
|
|
4
|
+
import os
|
|
5
|
+
from .common import _np_types, _top_level_sub_xds
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _write_zarr(xds: xr.Dataset, zarr_store: str):
|
|
9
|
+
xds_copy = xds.copy(deep=True)
|
|
10
|
+
sub_xds_dict = _encode(xds_copy, zarr_store)
|
|
11
|
+
z_obj = xds_copy.to_zarr(store=zarr_store, compute=True)
|
|
12
|
+
if sub_xds_dict:
|
|
13
|
+
_write_sub_xdses(sub_xds_dict)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _encode(xds: xr.Dataset, top_path: str) -> dict:
|
|
17
|
+
# encode attrs
|
|
18
|
+
sub_xds_dict = {}
|
|
19
|
+
_encode_dict(xds.attrs, top_path, sub_xds_dict)
|
|
20
|
+
for dv in xds.data_vars:
|
|
21
|
+
_encode_dict(xds[dv].attrs, os.sep.join([top_path, dv]), sub_xds_dict)
|
|
22
|
+
logging.debug(f"Encoded sub_xds_dict: {sub_xds_dict}")
|
|
23
|
+
return sub_xds_dict
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _encode_dict(my_dict: dict, top_path: str, sub_xds_dict) -> tuple:
|
|
27
|
+
del_keys = []
|
|
28
|
+
for k, v in my_dict.items():
|
|
29
|
+
if isinstance(v, dict):
|
|
30
|
+
z = os.sep.join([top_path, k])
|
|
31
|
+
_encode_dict(v, z, sub_xds_dict)
|
|
32
|
+
elif isinstance(v, np.ndarray):
|
|
33
|
+
my_dict[k] = {}
|
|
34
|
+
my_dict[k]["_type"] = "numpy.ndarray"
|
|
35
|
+
my_dict[k]["_value"] = v.tolist()
|
|
36
|
+
my_dict[k]["_dtype"] = str(v.dtype)
|
|
37
|
+
elif isinstance(v, xr.Dataset):
|
|
38
|
+
sub_xds_dict[os.sep.join([top_path, f"{_top_level_sub_xds}{k}"])] = v.copy(
|
|
39
|
+
deep=True
|
|
40
|
+
)
|
|
41
|
+
del_keys.append(k)
|
|
42
|
+
for k in del_keys:
|
|
43
|
+
del my_dict[k]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _write_sub_xdses(sub_xds: dict):
|
|
47
|
+
for k, v in sub_xds.items():
|
|
48
|
+
z_obj = v.to_zarr(store=k, compute=True)
|
|
@@ -48,7 +48,9 @@ def _load_casa_image_block(infile: str, block_des: dict, do_sky_coords) -> xr.Da
|
|
|
48
48
|
block = _get_persistent_block(
|
|
49
49
|
image_full_path, shapes, starts, dimorder, transpose_list, new_axes
|
|
50
50
|
)
|
|
51
|
-
xds = _add_sky_or_aperture(
|
|
51
|
+
xds = _add_sky_or_aperture(
|
|
52
|
+
xds, block, dimorder, image_full_path, ret["sphr_dims"], True
|
|
53
|
+
)
|
|
52
54
|
mymasks = _get_mask_names(image_full_path)
|
|
53
55
|
for m in mymasks:
|
|
54
56
|
full_path = os.sep.join([image_full_path, m])
|
|
@@ -57,7 +59,7 @@ def _load_casa_image_block(infile: str, block_des: dict, do_sky_coords) -> xr.Da
|
|
|
57
59
|
)
|
|
58
60
|
# data vars are all caps by convention
|
|
59
61
|
xds = _add_mask(xds, m.upper(), block, dimorder)
|
|
60
|
-
xds.attrs = _casa_image_to_xds_attrs(image_full_path
|
|
62
|
+
xds.attrs = _casa_image_to_xds_attrs(image_full_path)
|
|
61
63
|
mb = _multibeam_array(xds, image_full_path, False)
|
|
62
64
|
if mb is not None:
|
|
63
65
|
selectors = {}
|
|
@@ -86,6 +88,7 @@ def _read_casa_image(
|
|
|
86
88
|
dimorder,
|
|
87
89
|
img_full_path,
|
|
88
90
|
ret["sphr_dims"],
|
|
91
|
+
history,
|
|
89
92
|
)
|
|
90
93
|
if masks:
|
|
91
94
|
mymasks = _get_mask_names(img_full_path)
|
|
@@ -93,7 +96,7 @@ def _read_casa_image(
|
|
|
93
96
|
ary = _read_image_array(img_full_path, chunks, mask=m, verbose=verbose)
|
|
94
97
|
# data var names are all caps by convention
|
|
95
98
|
xds = _add_mask(xds, m.upper(), ary, dimorder)
|
|
96
|
-
xds.attrs = _casa_image_to_xds_attrs(img_full_path
|
|
99
|
+
xds.attrs = _casa_image_to_xds_attrs(img_full_path)
|
|
97
100
|
mb = _multibeam_array(xds, img_full_path, True)
|
|
98
101
|
if mb is not None:
|
|
99
102
|
xds["BEAM"] = mb
|
|
@@ -17,7 +17,8 @@ from xradio.measurement_set._utils._msv2._tables.read import (
|
|
|
17
17
|
make_taql_where_between_min_max,
|
|
18
18
|
load_generic_table,
|
|
19
19
|
)
|
|
20
|
-
from xradio._utils.list_and_array import cast_to_str
|
|
20
|
+
from xradio._utils.list_and_array import cast_to_str, get_pad_value
|
|
21
|
+
|
|
21
22
|
from xradio._utils.coord_math import (
|
|
22
23
|
convert_to_si_units,
|
|
23
24
|
add_position_offsets,
|
|
@@ -547,10 +548,16 @@ def pad_missing_sources(
|
|
|
547
548
|
for source_id in unique_source_ids
|
|
548
549
|
if source_id not in source_xds.coords["SOURCE_ID"]
|
|
549
550
|
]
|
|
551
|
+
if len(missing_source_ids) < 1:
|
|
552
|
+
return source_xds
|
|
550
553
|
|
|
551
554
|
# would like to use the new-ish xr.pad, but it creates issues with indices/coords and is
|
|
552
555
|
# also not free of overheads, as it for example changes all numeric types to float64
|
|
553
|
-
|
|
556
|
+
fill_value = {
|
|
557
|
+
var_name: get_pad_value(var.dtype)
|
|
558
|
+
for var_name, var in source_xds.data_vars.items()
|
|
559
|
+
}
|
|
560
|
+
missing_source_xds = xr.full_like(source_xds.isel(SOURCE_ID=0), fill_value)
|
|
554
561
|
pad_str = "Unknown"
|
|
555
562
|
pad_str_type = "<U9"
|
|
556
563
|
for var in missing_source_xds.data_vars:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: xradio
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.52
|
|
4
4
|
Summary: Xarray Radio Astronomy Data IO
|
|
5
5
|
Author-email: Jan-Willem Steeb <jsteeb@nrao.edu>, Federico Montesino Pouzols <pouzols@eso.edu>, Dave Mehringer <dmehring@nrao.edu>, Peter Wortmann <peter.wortmann@skao.int>
|
|
6
6
|
License: BSD 3-Clause License
|
|
@@ -80,9 +80,9 @@ Dynamic: license-file
|
|
|
80
80
|
Xarray Radio Astronomy Data IO is still in development.
|
|
81
81
|
|
|
82
82
|
[](https://www.python.org/downloads/release/python-3130/)
|
|
83
|
-

|
|
84
|
-

|
|
85
|
-

|
|
83
|
+
[](https://github.com/casangi/xradio/actions/workflows/python-testing-linux.yml?query=branch%3Amain)
|
|
84
|
+
[](https://github.com/casangi/xradio/actions/workflows/python-testing-macos.yml?query=branch%3Amain)
|
|
85
|
+
[](https://github.com/casangi/xradio/actions/workflows/run-ipynb.yml?query=branch%3Amain)
|
|
86
86
|
[](https://codecov.io/gh/casangi/xradio/branch/main/xradio)
|
|
87
87
|
[](https://xradio.readthedocs.io)
|
|
88
88
|
[](https://pypi.python.org/pypi/xradio/)
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
import xarray as xr
|
|
3
|
-
import os
|
|
4
|
-
from .common import _np_types, _top_level_sub_xds
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def _write_zarr(xds: xr.Dataset, zarr_store: str):
|
|
8
|
-
xds_copy = xds.copy(deep=True)
|
|
9
|
-
xds_copy, xds_dict = _encode(xds_copy)
|
|
10
|
-
z_obj = xds_copy.to_zarr(store=zarr_store, compute=True)
|
|
11
|
-
_write_sub_xdses(zarr_store, xds_dict, _top_level_sub_xds)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def _encode(xds: xr.Dataset):
|
|
15
|
-
# encode attrs
|
|
16
|
-
xds.attrs, xds_dict = _encode_dict(xds.attrs)
|
|
17
|
-
return xds, xds_dict
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def _encode_dict(my_dict: dict, top_key="") -> tuple:
|
|
21
|
-
xds_dict = {}
|
|
22
|
-
del_keys = []
|
|
23
|
-
for k, v in my_dict.items():
|
|
24
|
-
if isinstance(v, dict):
|
|
25
|
-
z = os.sep.join([top_key, k]) if top_key else k
|
|
26
|
-
my_dict[k], ret_xds_dict = _encode_dict(v, z)
|
|
27
|
-
if ret_xds_dict:
|
|
28
|
-
xds_dict[k] = ret_xds_dict
|
|
29
|
-
elif isinstance(v, np.ndarray):
|
|
30
|
-
my_dict[k] = {}
|
|
31
|
-
my_dict[k]["_type"] = "numpy.ndarray"
|
|
32
|
-
my_dict[k]["_value"] = v.tolist()
|
|
33
|
-
my_dict[k]["_dtype"] = str(v.dtype)
|
|
34
|
-
elif isinstance(v, xr.Dataset):
|
|
35
|
-
xds_dict[k] = v.copy(deep=True)
|
|
36
|
-
del_keys.append(k)
|
|
37
|
-
for k in del_keys:
|
|
38
|
-
del my_dict[k]
|
|
39
|
-
return my_dict, xds_dict
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
def _write_sub_xdses(zarr_store: str, xds_dict: dict, path: str):
|
|
43
|
-
for k, v in xds_dict.items():
|
|
44
|
-
my_path = f"{path}_{k}" if path else f"{k}"
|
|
45
|
-
if isinstance(v, dict):
|
|
46
|
-
_write_sub_xdses(zarr_store, xds_dict[k], my_path)
|
|
47
|
-
elif isinstance(v, xr.Dataset):
|
|
48
|
-
zs = os.sep.join([zarr_store, my_path])
|
|
49
|
-
z_obj = v.to_zarr(store=zs, compute=True)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_msv2/_tables/load_main_table.py
RENAMED
|
File without changes
|
|
File without changes
|
{xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_msv2/_tables/read_main_table.py
RENAMED
|
File without changes
|
{xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_msv2/_tables/read_subtables.py
RENAMED
|
File without changes
|
{xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_msv2/_tables/table_query.py
RENAMED
|
File without changes
|
|
File without changes
|
{xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_msv2/_tables/write_exp_api.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_msv2/create_antenna_xds.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_msv2/msv2_to_msv4_meta.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_msv2/optimised_functions.py
RENAMED
|
File without changes
|
{xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/_utils/_msv2/partition_queries.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{xradio-0.0.51 → xradio-0.0.52}/src/xradio/measurement_set/convert_msv2_to_processing_set.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|