xradio 0.0.50__py3-none-any.whl → 0.0.52__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/dict_helpers.py +24 -0
- xradio/_utils/schema.py +2 -2
- xradio/image/_util/_casacore/xds_from_casacore.py +116 -69
- xradio/image/_util/_casacore/xds_to_casacore.py +51 -32
- xradio/image/_util/_fits/xds_from_fits.py +43 -52
- xradio/image/_util/_zarr/common.py +1 -1
- xradio/image/_util/_zarr/xds_from_zarr.py +37 -20
- xradio/image/_util/_zarr/xds_to_zarr.py +20 -21
- xradio/image/_util/casacore.py +6 -3
- xradio/measurement_set/_utils/_msv2/conversion.py +3 -3
- xradio/measurement_set/_utils/_msv2/create_antenna_xds.py +5 -5
- xradio/measurement_set/_utils/_msv2/create_field_and_source_xds.py +11 -3
- xradio/measurement_set/_utils/_msv2/msv4_sub_xdss.py +151 -13
- xradio/measurement_set/processing_set_xdt.py +146 -31
- xradio/measurement_set/schema.py +40 -25
- {xradio-0.0.50.dist-info → xradio-0.0.52.dist-info}/METADATA +10 -4
- {xradio-0.0.50.dist-info → xradio-0.0.52.dist-info}/RECORD +20 -20
- {xradio-0.0.50.dist-info → xradio-0.0.52.dist-info}/WHEEL +1 -1
- {xradio-0.0.50.dist-info → xradio-0.0.52.dist-info}/licenses/LICENSE.txt +0 -0
- {xradio-0.0.50.dist-info → xradio-0.0.52.dist-info}/top_level.txt +0 -0
xradio/_utils/dict_helpers.py
CHANGED
|
@@ -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
|
xradio/_utils/schema.py
CHANGED
|
@@ -190,14 +190,14 @@ casacore_to_msv4_measure_type = {
|
|
|
190
190
|
"LSRK": "lsrk",
|
|
191
191
|
"LSRD": "lsrd",
|
|
192
192
|
"BARY": "BARY",
|
|
193
|
-
"GEO": "
|
|
193
|
+
"GEO": "gcrs",
|
|
194
194
|
"TOPO": "TOPO",
|
|
195
195
|
}, # The frames/observer we are not sure if/how to translate to astropy are uppercase
|
|
196
196
|
},
|
|
197
197
|
"position": {
|
|
198
198
|
"type": "location",
|
|
199
199
|
"Ref": "frame",
|
|
200
|
-
"Ref_map": {"ITRF": "
|
|
200
|
+
"Ref_map": {"ITRF": "ITRS"},
|
|
201
201
|
},
|
|
202
202
|
"uvw": {
|
|
203
203
|
"type": "uvw",
|
|
@@ -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
|
|