xradio 1.0.2__py3-none-any.whl → 1.1.1__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 +75 -9
- 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 +144 -92
- xradio/image/_util/_casacore/xds_to_casacore.py +118 -53
- xradio/image/_util/_fits/xds_from_fits.py +125 -37
- xradio/image/_util/_zarr/common.py +0 -1
- xradio/image/_util/casacore.py +183 -25
- xradio/image/_util/common.py +10 -8
- xradio/image/_util/image_factory.py +469 -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 +4 -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.1.dist-info}/METADATA +65 -23
- xradio-1.1.1.dist-info/RECORD +75 -0
- {xradio-1.0.2.dist-info → xradio-1.1.1.dist-info}/WHEEL +1 -1
- xradio-1.0.2.dist-info/RECORD +0 -66
- {xradio-1.0.2.dist-info → xradio-1.1.1.dist-info}/licenses/LICENSE.txt +0 -0
- {xradio-1.0.2.dist-info → xradio-1.1.1.dist-info}/top_level.txt +0 -0
|
@@ -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,
|
|
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
|
|
|
@@ -272,41 +285,76 @@ def _casa_image_to_xds_attrs(img_full_path: str) -> dict:
|
|
|
272
285
|
raise RuntimeError("No direction reference frame found")
|
|
273
286
|
casa_system = coord_dir_dict[system]
|
|
274
287
|
ap_system, ap_equinox = _convert_direction_system(casa_system, "native")
|
|
275
|
-
dir_dict = {}
|
|
276
288
|
|
|
277
|
-
|
|
278
|
-
|
|
289
|
+
coordinate_system_info = {}
|
|
290
|
+
|
|
291
|
+
unit0 = u.Unit(_get_unit(coord_dir_dict["units"][0]))
|
|
292
|
+
unit1 = u.Unit(_get_unit(coord_dir_dict["units"][1]))
|
|
293
|
+
ra = float((coord_dir_dict["crval"][0] * unit0).to("rad").value)
|
|
294
|
+
dec = float((coord_dir_dict["crval"][1] * unit1).to("rad").value)
|
|
295
|
+
coordinate_system_info["reference_direction"] = make_skycoord_dict(
|
|
296
|
+
data=[ra, dec], units="rad", frame=ap_system
|
|
279
297
|
)
|
|
280
298
|
if ap_equinox:
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
299
|
+
coordinate_system_info["reference_direction"]["attrs"][
|
|
300
|
+
"equinox"
|
|
301
|
+
] = ap_equinox
|
|
302
|
+
|
|
303
|
+
pol_dir = [-1, coord_dir_dict["latpole"] * _deg_to_rad]
|
|
304
|
+
if "lonpole" in coord_dir_dict:
|
|
305
|
+
pol_dir[0] = coord_dir_dict["lonpole"] * _deg_to_rad
|
|
306
|
+
else:
|
|
307
|
+
pol_dir[0] = coord_dir_dict["longpole"] * _deg_to_rad
|
|
308
|
+
|
|
309
|
+
coordinate_system_info["native_pole_direction"] = make_direction_location_dict(
|
|
310
|
+
pol_dir, "rad", "native_projection"
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
coordinate_system_info["projection"] = coord_dir_dict["projection"]
|
|
314
|
+
coordinate_system_info["projection_parameters"] = to_python_type(
|
|
315
|
+
coord_dir_dict["projection_parameters"]
|
|
316
|
+
)
|
|
317
|
+
coordinate_system_info["pixel_coordinate_transformation_matrix"] = (
|
|
318
|
+
to_python_type(coord_dir_dict["pc"])
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
attrs["coordinate_system_info"] = coordinate_system_info
|
|
298
322
|
return copy.deepcopy(attrs)
|
|
299
323
|
|
|
324
|
+
# dir_dict = {}
|
|
325
|
+
|
|
326
|
+
# dir_dict["reference"] = make_skycoord_dict(
|
|
327
|
+
# data=[0.0, 0.0], units="rad", frame=ap_system
|
|
328
|
+
# )
|
|
329
|
+
# if ap_equinox:
|
|
330
|
+
# dir_dict["reference"]["attrs"]["equinox"] = ap_equinox
|
|
331
|
+
# for i in range(2):
|
|
332
|
+
# unit = u.Unit(_get_unit(coord_dir_dict["units"][i]))
|
|
333
|
+
# q = coord_dir_dict["crval"][i] * unit
|
|
334
|
+
# x = q.to("rad")
|
|
335
|
+
# dir_dict["reference"]["data"][i] = float(x.value)
|
|
336
|
+
# k = "latpole"
|
|
337
|
+
# if k in coord_dir_dict:
|
|
338
|
+
# for j in (k, "lonpole"):
|
|
339
|
+
# m = "longpole" if j == "lonpole" else j
|
|
340
|
+
# dir_dict[j] = make_quantity(
|
|
341
|
+
# value=coord_dir_dict[m] * _deg_to_rad, units="rad", dims=["l", "m"]
|
|
342
|
+
# )
|
|
343
|
+
# for j in ("pc", "projection_parameters", "projection"):
|
|
344
|
+
# if j in coord_dir_dict:
|
|
345
|
+
# dir_dict[j] = coord_dir_dict[j]
|
|
346
|
+
# attrs["direction"] = dir_dict
|
|
347
|
+
# return copy.deepcopy(attrs)
|
|
348
|
+
|
|
300
349
|
|
|
301
350
|
def _casa_image_to_xds_coords(
|
|
302
|
-
img_full_path: str, verbose: bool, do_sky_coords: bool
|
|
351
|
+
img_full_path: str, verbose: bool, do_sky_coords: bool, image_type: str
|
|
303
352
|
) -> dict:
|
|
304
353
|
"""
|
|
305
354
|
TODO: complete documentation
|
|
306
355
|
Create an xds without any pixel data from metadata from the specified CASA image
|
|
307
356
|
"""
|
|
308
357
|
attrs = {}
|
|
309
|
-
# casa_image = images.image(img_full_path)
|
|
310
358
|
with _open_image_ro(img_full_path) as casa_image:
|
|
311
359
|
# shape list is the reverse of the actual image shape
|
|
312
360
|
shape = casa_image.shape()[::-1]
|
|
@@ -330,57 +378,56 @@ def _casa_image_to_xds_coords(
|
|
|
330
378
|
attrs["sphr_dims"] = sphr_dims
|
|
331
379
|
coords = {}
|
|
332
380
|
coord_attrs = {}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
)
|
|
337
|
-
(velocity_vals, coord_attrs["velocity"]) = _get_velocity_values_attrs(
|
|
381
|
+
coords["time"], coord_attrs["time"] = _get_time_values_attrs(coord_dict)
|
|
382
|
+
coords["frequency"], coord_attrs["frequency"] = _get_freq_values_attrs(csys, shape)
|
|
383
|
+
velocity_vals, coord_attrs["velocity"] = _get_velocity_values_attrs(
|
|
338
384
|
coord_dict, coords["frequency"]
|
|
339
385
|
)
|
|
340
|
-
|
|
386
|
+
coords["polarization"], coord_attrs["polarization"] = _get_pol_values_attrs(
|
|
341
387
|
coord_dict
|
|
342
388
|
)
|
|
343
389
|
coords["velocity"] = (["frequency"], velocity_vals)
|
|
344
|
-
if
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
390
|
+
if image_type.upper() != "VISIBILITY_NORMALIZATION":
|
|
391
|
+
if len(sphr_dims) > 0:
|
|
392
|
+
crpix = _flatten_list(csys.get_referencepixel())[::-1]
|
|
393
|
+
inc = _flatten_list(csys.get_increment())[::-1]
|
|
394
|
+
unit = _flatten_list(csys.get_unit())[::-1]
|
|
395
|
+
attr_note = _l_m_attr_notes()
|
|
396
|
+
for c in ["l", "m"]:
|
|
397
|
+
idx = dimmap[c]
|
|
398
|
+
delta = ((inc[idx]) * u.Unit(_get_unit(unit[idx]))).to("rad").value
|
|
399
|
+
coords[c] = _compute_linear_world_values(
|
|
400
|
+
naxis=shape[idx], crval=0.0, crpix=crpix[idx], cdelt=delta
|
|
401
|
+
)
|
|
402
|
+
coord_attrs[c] = {
|
|
403
|
+
"note": attr_note[c],
|
|
404
|
+
}
|
|
405
|
+
if do_sky_coords:
|
|
406
|
+
for k in coord_dict.keys():
|
|
407
|
+
if k.startswith("direction"):
|
|
408
|
+
dc = coordinates.directioncoordinate(coord_dict[k])
|
|
409
|
+
break
|
|
410
|
+
crval = _flatten_list(csys.get_referencevalue())[::-1]
|
|
411
|
+
pick = lambda my_list: [my_list[i] for i in sphr_dims]
|
|
412
|
+
my_ret = _compute_world_sph_dims(
|
|
413
|
+
projection=dc.get_projection(),
|
|
414
|
+
shape=pick(shape),
|
|
415
|
+
ctype=diraxes,
|
|
416
|
+
crval=pick(crval),
|
|
417
|
+
crpix=pick(crpix),
|
|
418
|
+
cdelt=pick(inc),
|
|
419
|
+
cunit=pick(unit),
|
|
420
|
+
)
|
|
421
|
+
for i in [0, 1]:
|
|
422
|
+
axis_name = my_ret["axis_name"][i]
|
|
423
|
+
coords[axis_name] = (["l", "m"], my_ret["value"][i])
|
|
424
|
+
coord_attrs[axis_name] = {}
|
|
425
|
+
else:
|
|
426
|
+
# Fourier image
|
|
427
|
+
ret = _get_uv_values_attrs(coord_dict, axis_names, shape)
|
|
428
|
+
for z in ["u", "v"]:
|
|
429
|
+
coords[z], coord_attrs[z] = ret[z]
|
|
430
|
+
coords["beam_params_label"] = ["major", "minor", "pa"]
|
|
384
431
|
attrs["shape"] = shape
|
|
385
432
|
xds = xr.Dataset(coords=coords)
|
|
386
433
|
for c in coord_attrs.keys():
|
|
@@ -390,7 +437,7 @@ def _casa_image_to_xds_coords(
|
|
|
390
437
|
|
|
391
438
|
|
|
392
439
|
def _convert_direction_system(
|
|
393
|
-
casa_system: str, which: str, verbose: bool =
|
|
440
|
+
casa_system: str, which: str, verbose: bool = False
|
|
394
441
|
) -> tuple:
|
|
395
442
|
if casa_system == "J2000":
|
|
396
443
|
if verbose:
|
|
@@ -634,6 +681,7 @@ def _get_persistent_block(
|
|
|
634
681
|
block = _read_image_chunk(infile, shapes, starts)
|
|
635
682
|
block = np.expand_dims(block, new_axes)
|
|
636
683
|
block = block.transpose(transpose_list)
|
|
684
|
+
block = da.from_array(block, chunks=block.shape)
|
|
637
685
|
block = xr.DataArray(block, dims=dimorder)
|
|
638
686
|
return block
|
|
639
687
|
|
|
@@ -686,11 +734,11 @@ def _get_starts_shapes_slices(
|
|
|
686
734
|
def _get_time_values_attrs(cimage_coord_dict: dict) -> Tuple[List[float], dict]:
|
|
687
735
|
attrs = {}
|
|
688
736
|
attrs["type"] = "time"
|
|
689
|
-
attrs["scale"] = cimage_coord_dict["obsdate"]["refer"]
|
|
737
|
+
attrs["scale"] = cimage_coord_dict["obsdate"]["refer"].lower()
|
|
690
738
|
unit = cimage_coord_dict["obsdate"]["m0"]["unit"]
|
|
691
739
|
attrs["units"] = unit
|
|
692
740
|
time_val = cimage_coord_dict["obsdate"]["m0"]["value"]
|
|
693
|
-
attrs["format"] = _get_time_format(time_val, unit)
|
|
741
|
+
attrs["format"] = _get_time_format(time_val, unit).lower()
|
|
694
742
|
return ([time_val], copy.deepcopy(attrs))
|
|
695
743
|
|
|
696
744
|
|
|
@@ -829,7 +877,11 @@ def _get_velocity_values_attrs(
|
|
|
829
877
|
|
|
830
878
|
|
|
831
879
|
def _get_beam(
|
|
832
|
-
img_full_path: str,
|
|
880
|
+
img_full_path: str,
|
|
881
|
+
nchan: int,
|
|
882
|
+
npol: int,
|
|
883
|
+
as_dask_array: bool,
|
|
884
|
+
image_type: str = "SKY",
|
|
833
885
|
) -> Union[xr.DataArray, None]:
|
|
834
886
|
# the image may have multiple beams
|
|
835
887
|
with _open_image_ro(img_full_path) as casa_image:
|
|
@@ -862,10 +914,10 @@ def _get_beam(
|
|
|
862
914
|
if as_dask_array:
|
|
863
915
|
beam_array = da.array(beam_array)
|
|
864
916
|
xdb = xr.DataArray(
|
|
865
|
-
beam_array, dims=["time", "frequency", "polarization", "
|
|
917
|
+
beam_array, dims=["time", "frequency", "polarization", "beam_params_label"]
|
|
866
918
|
)
|
|
867
|
-
xdb = xdb.rename("
|
|
868
|
-
xdb = xdb.assign_coords(
|
|
919
|
+
xdb = xdb.rename("BEAM_FIT_PARAMS_" + image_type.upper())
|
|
920
|
+
xdb = xdb.assign_coords(beam_params_label=["major", "minor", "pa"])
|
|
869
921
|
xdb.attrs["units"] = "rad"
|
|
870
922
|
return xdb
|
|
871
923
|
|
|
@@ -1054,7 +1106,7 @@ def _read_image_array(
|
|
|
1054
1106
|
indicating the length of a chunk on that particular axis. If
|
|
1055
1107
|
a key is missing, the associated chunk length along that axis
|
|
1056
1108
|
is 1. 'l' represents the longitude like dimension, and 'm'
|
|
1057
|
-
represents the latitude like dimension. For
|
|
1109
|
+
represents the latitude like dimension. For aperture images,
|
|
1058
1110
|
'u' may be used in place of 'l', and 'v' in place of 'm'.
|
|
1059
1111
|
:type chunks: list | dict, required
|
|
1060
1112
|
:param mask: If specified, this is the associated image mask to read, rather than the actual
|