xradio 0.0.48__py3-none-any.whl → 0.0.49__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/__init__.py +1 -0
- xradio/_utils/dict_helpers.py +69 -2
- xradio/image/_util/__init__.py +0 -3
- xradio/image/_util/_casacore/common.py +0 -13
- xradio/image/_util/_casacore/xds_from_casacore.py +102 -97
- xradio/image/_util/_casacore/xds_to_casacore.py +36 -24
- xradio/image/_util/_fits/xds_from_fits.py +81 -36
- xradio/image/_util/_zarr/zarr_low_level.py +3 -3
- xradio/image/_util/casacore.py +7 -5
- xradio/image/_util/common.py +13 -26
- xradio/image/_util/image_factory.py +143 -191
- xradio/image/image.py +10 -59
- xradio/measurement_set/__init__.py +11 -6
- xradio/measurement_set/_utils/_msv2/_tables/read.py +187 -46
- xradio/measurement_set/_utils/_msv2/_tables/table_query.py +22 -0
- xradio/measurement_set/_utils/_msv2/conversion.py +351 -318
- xradio/measurement_set/_utils/_msv2/msv4_info_dicts.py +20 -17
- xradio/measurement_set/convert_msv2_to_processing_set.py +46 -6
- xradio/measurement_set/load_processing_set.py +100 -53
- xradio/measurement_set/measurement_set_xdt.py +197 -0
- xradio/measurement_set/open_processing_set.py +122 -86
- xradio/measurement_set/processing_set_xdt.py +1552 -0
- xradio/measurement_set/schema.py +199 -94
- xradio/schema/bases.py +5 -1
- xradio/schema/check.py +97 -5
- {xradio-0.0.48.dist-info → xradio-0.0.49.dist-info}/METADATA +4 -4
- {xradio-0.0.48.dist-info → xradio-0.0.49.dist-info}/RECORD +30 -30
- {xradio-0.0.48.dist-info → xradio-0.0.49.dist-info}/WHEEL +1 -1
- xradio/measurement_set/measurement_set_xds.py +0 -117
- xradio/measurement_set/processing_set.py +0 -803
- {xradio-0.0.48.dist-info → xradio-0.0.49.dist-info/licenses}/LICENSE.txt +0 -0
- {xradio-0.0.48.dist-info → xradio-0.0.49.dist-info}/top_level.txt +0 -0
|
@@ -16,7 +16,11 @@ from ..common import (
|
|
|
16
16
|
_l_m_attr_notes,
|
|
17
17
|
)
|
|
18
18
|
from xradio._utils.coord_math import _deg_to_rad
|
|
19
|
-
from xradio._utils.dict_helpers import
|
|
19
|
+
from xradio._utils.dict_helpers import (
|
|
20
|
+
make_quantity,
|
|
21
|
+
make_frequency_reference_dict,
|
|
22
|
+
make_skycoord_dict,
|
|
23
|
+
)
|
|
20
24
|
import copy
|
|
21
25
|
import dask
|
|
22
26
|
import dask.array as da
|
|
@@ -50,6 +54,8 @@ def _fits_image_to_xds(
|
|
|
50
54
|
xds = _add_coord_attrs(xds, helpers)
|
|
51
55
|
if helpers["has_multibeam"]:
|
|
52
56
|
xds = _do_multibeam(xds, img_full_path)
|
|
57
|
+
elif "beam" in helpers and helpers["beam"] is not None:
|
|
58
|
+
xds = _add_beam(xds, helpers)
|
|
53
59
|
return xds
|
|
54
60
|
|
|
55
61
|
|
|
@@ -66,6 +72,7 @@ def _add_time_attrs(xds: xr.Dataset, helpers: dict) -> xr.Dataset:
|
|
|
66
72
|
time_coord = xds.coords["time"]
|
|
67
73
|
meta = copy.deepcopy(helpers["obsdate"])
|
|
68
74
|
del meta["value"]
|
|
75
|
+
# meta["units"] = [ meta["units"] ]
|
|
69
76
|
# meta['format'] = 'MJD'
|
|
70
77
|
# meta['time_scale'] = meta['refer']
|
|
71
78
|
# del meta['refer']
|
|
@@ -79,13 +86,16 @@ def _add_freq_attrs(xds: xr.Dataset, helpers: dict) -> xr.Dataset:
|
|
|
79
86
|
meta = {}
|
|
80
87
|
if helpers["has_freq"]:
|
|
81
88
|
meta["rest_frequency"] = make_quantity(helpers["restfreq"], "Hz")
|
|
82
|
-
meta["
|
|
83
|
-
meta["
|
|
89
|
+
meta["rest_frequencies"] = [meta["rest_frequency"]]
|
|
90
|
+
# meta["frame"] = helpers["specsys"]
|
|
91
|
+
# meta["units"] = "Hz"
|
|
84
92
|
meta["type"] = "frequency"
|
|
85
93
|
meta["wave_unit"] = "mm"
|
|
86
94
|
freq_axis = helpers["freq_axis"]
|
|
87
|
-
meta["
|
|
88
|
-
|
|
95
|
+
meta["reference_value"] = make_frequency_reference_dict(
|
|
96
|
+
helpers["crval"][freq_axis], ["Hz"], helpers["specsys"]
|
|
97
|
+
)
|
|
98
|
+
# meta["cdelt"] = helpers["cdelt"][freq_axis]
|
|
89
99
|
if not meta:
|
|
90
100
|
# this is the default frequency information CASA creates
|
|
91
101
|
meta = _default_freq_info()
|
|
@@ -96,7 +106,7 @@ def _add_freq_attrs(xds: xr.Dataset, helpers: dict) -> xr.Dataset:
|
|
|
96
106
|
|
|
97
107
|
def _add_vel_attrs(xds: xr.Dataset, helpers: dict) -> xr.Dataset:
|
|
98
108
|
vel_coord = xds.coords["velocity"]
|
|
99
|
-
meta = {"units": "m/s"}
|
|
109
|
+
meta = {"units": ["m/s"]}
|
|
100
110
|
if helpers["has_freq"]:
|
|
101
111
|
meta["doppler_type"] = helpers.get("doppler", "RADIO")
|
|
102
112
|
else:
|
|
@@ -112,10 +122,6 @@ def _add_l_m_attrs(xds: xr.Dataset, helpers: dict) -> xr.Dataset:
|
|
|
112
122
|
for c in ["l", "m"]:
|
|
113
123
|
if c in xds.coords:
|
|
114
124
|
xds[c].attrs = {
|
|
115
|
-
"crval": 0.0,
|
|
116
|
-
"cdelt": helpers[c]["cdelt"],
|
|
117
|
-
"units": "rad",
|
|
118
|
-
"type": "quantity",
|
|
119
125
|
"note": attr_note[c],
|
|
120
126
|
}
|
|
121
127
|
return xds
|
|
@@ -167,6 +173,10 @@ def _xds_direction_attrs_from_header(helpers: dict, header) -> dict:
|
|
|
167
173
|
helpers["ref_sys"] = ref_sys
|
|
168
174
|
helpers["ref_eqx"] = ref_eqx
|
|
169
175
|
# fits does not support conversion frames
|
|
176
|
+
direction["reference"] = make_skycoord_dict(
|
|
177
|
+
[0.0, 0.0], units=["rad", "rad"], frame=ref_sys
|
|
178
|
+
)
|
|
179
|
+
"""
|
|
170
180
|
direction["reference"] = {
|
|
171
181
|
"type": "sky_coord",
|
|
172
182
|
"frame": ref_sys,
|
|
@@ -174,20 +184,39 @@ def _xds_direction_attrs_from_header(helpers: dict, header) -> dict:
|
|
|
174
184
|
"units": ["rad", "rad"],
|
|
175
185
|
"value": [0.0, 0.0],
|
|
176
186
|
}
|
|
187
|
+
"""
|
|
177
188
|
dir_axes = helpers["dir_axes"]
|
|
189
|
+
ddata = []
|
|
190
|
+
dunits = []
|
|
178
191
|
for i in dir_axes:
|
|
179
192
|
x = helpers["crval"][i] * u.Unit(_get_unit(helpers["cunit"][i]))
|
|
180
193
|
x = x.to("rad")
|
|
181
|
-
|
|
194
|
+
ddata.append(x.value)
|
|
195
|
+
# direction["reference"]["value"][i] = x.value
|
|
182
196
|
x = helpers["cdelt"][i] * u.Unit(_get_unit(helpers["cunit"][i]))
|
|
183
|
-
x
|
|
184
|
-
direction["
|
|
185
|
-
direction["
|
|
197
|
+
dunits.append(x.to("rad"))
|
|
198
|
+
direction["reference"] = make_skycoord_dict(ddata, units=dunits, frame=ref_sys)
|
|
199
|
+
direction["reference"]["attrs"]["equinox"] = ref_eqx.lower()
|
|
200
|
+
direction["latpole"] = make_quantity(
|
|
201
|
+
header["LATPOLE"] * _deg_to_rad, "rad", dims=["l", "m"]
|
|
202
|
+
)
|
|
203
|
+
direction["lonpole"] = make_quantity(
|
|
204
|
+
header["LONPOLE"] * _deg_to_rad, "rad", dims=["l", "m"]
|
|
205
|
+
)
|
|
186
206
|
pc = np.zeros([2, 2])
|
|
187
207
|
for i in (0, 1):
|
|
188
208
|
for j in (0, 1):
|
|
189
209
|
# dir_axes are now 0-based, but fits needs 1-based
|
|
190
|
-
|
|
210
|
+
try:
|
|
211
|
+
pc[i][j] = header[f"PC{dir_axes[i]+1}_{dir_axes[j]+1}"]
|
|
212
|
+
except KeyError:
|
|
213
|
+
try:
|
|
214
|
+
pc[i][j] = header[f"PC0{dir_axes[i]+1}_0{dir_axes[j]+1}"]
|
|
215
|
+
except KeyError:
|
|
216
|
+
raise RuntimeError(
|
|
217
|
+
f"Could not find PC{dir_axes[i]+1}_{dir_axes[j]+1} or "
|
|
218
|
+
f"PC0{dir_axes[i]+1}_0{dir_axes[j]+1} in FITS header"
|
|
219
|
+
)
|
|
191
220
|
direction["pc"] = pc
|
|
192
221
|
# Is there really no fits header parameter for projection_parameters?
|
|
193
222
|
direction["projection_parameters"] = np.array([0.0, 0.0])
|
|
@@ -314,9 +343,9 @@ def _beam_attr_from_header(helpers: dict, header) -> Union[dict, str, None]:
|
|
|
314
343
|
if "BMAJ" in header:
|
|
315
344
|
# single global beam
|
|
316
345
|
beam = {
|
|
317
|
-
"bmaj": make_quantity(header["BMAJ"], "
|
|
318
|
-
"bmin": make_quantity(header["BMIN"], "
|
|
319
|
-
"pa": make_quantity(header["BPA"], "
|
|
346
|
+
"bmaj": make_quantity(header["BMAJ"], "deg"),
|
|
347
|
+
"bmin": make_quantity(header["BMIN"], "deg"),
|
|
348
|
+
"pa": make_quantity(header["BPA"], "deg"),
|
|
320
349
|
}
|
|
321
350
|
return _convert_beam_to_rad(beam)
|
|
322
351
|
elif "CASAMBM" in header and header["CASAMBM"]:
|
|
@@ -390,11 +419,11 @@ def _fits_header_to_xds_attrs(hdulist: fits.hdu.hdulist.HDUList) -> dict:
|
|
|
390
419
|
attrs["direction"] = _xds_direction_attrs_from_header(helpers, header)
|
|
391
420
|
# FIXME read fits data in chunks in case all data too large to hold in memory
|
|
392
421
|
has_mask = da.any(da.isnan(primary.data)).compute()
|
|
393
|
-
attrs["active_mask"] = "
|
|
422
|
+
attrs["active_mask"] = "MASK0" if has_mask else None
|
|
394
423
|
helpers["has_mask"] = has_mask
|
|
395
424
|
beam = _beam_attr_from_header(helpers, header)
|
|
396
425
|
if beam != "mb":
|
|
397
|
-
|
|
426
|
+
helpers["beam"] = beam
|
|
398
427
|
if "BITPIX" in header:
|
|
399
428
|
v = abs(header["BITPIX"])
|
|
400
429
|
if v == 32:
|
|
@@ -409,7 +438,7 @@ def _fits_header_to_xds_attrs(hdulist: fits.hdu.hdulist.HDUList) -> dict:
|
|
|
409
438
|
obsdate = {}
|
|
410
439
|
obsdate["type"] = "time"
|
|
411
440
|
obsdate["value"] = Time(header["DATE-OBS"], format="isot").mjd
|
|
412
|
-
obsdate["units"] = "d"
|
|
441
|
+
obsdate["units"] = ["d"]
|
|
413
442
|
obsdate["scale"] = header["TIMESYS"]
|
|
414
443
|
obsdate["format"] = "MJD"
|
|
415
444
|
attrs["obsdate"] = obsdate
|
|
@@ -453,8 +482,8 @@ def _create_coords(
|
|
|
453
482
|
helpers["sphr_dims"] = sphr_dims
|
|
454
483
|
coords = {}
|
|
455
484
|
coords["time"] = _get_time_values(helpers)
|
|
456
|
-
coords["polarization"] = _get_pol_values(helpers)
|
|
457
485
|
coords["frequency"] = _get_freq_values(helpers)
|
|
486
|
+
coords["polarization"] = _get_pol_values(helpers)
|
|
458
487
|
coords["velocity"] = (["frequency"], _get_velocity_values(helpers))
|
|
459
488
|
if len(sphr_dims) > 0:
|
|
460
489
|
for i, c in enumerate(["l", "m"]):
|
|
@@ -497,6 +526,7 @@ def _create_coords(
|
|
|
497
526
|
else:
|
|
498
527
|
# Fourier image
|
|
499
528
|
coords["u"], coords["v"] = _get_uv_values(helpers)
|
|
529
|
+
coords["beam_param"] = ["major", "minor", "pa"]
|
|
500
530
|
xds = xr.Dataset(coords=coords)
|
|
501
531
|
return xds
|
|
502
532
|
|
|
@@ -615,28 +645,43 @@ def _do_multibeam(xds: xr.Dataset, imname: str) -> xr.Dataset:
|
|
|
615
645
|
)
|
|
616
646
|
nchan = header["NCHAN"]
|
|
617
647
|
npol = header["NPOL"]
|
|
618
|
-
beam_array = np.zeros([1,
|
|
648
|
+
beam_array = np.zeros([1, nchan, npol, 3])
|
|
619
649
|
data = hdu.data
|
|
650
|
+
hdulist.close()
|
|
620
651
|
for t in data:
|
|
621
|
-
beam_array[0, t[
|
|
652
|
+
beam_array[0, t[3], t[4]] = t[0:3]
|
|
622
653
|
for i in (0, 1, 2):
|
|
623
654
|
beam_array[:, :, :, i] = (
|
|
624
655
|
(beam_array[:, :, :, i] * units[i]).to("rad").value
|
|
625
656
|
)
|
|
626
|
-
|
|
627
|
-
beam_array, dims=["time", "polarization", "frequency", "beam_param"]
|
|
628
|
-
)
|
|
629
|
-
xdb = xdb.rename("beam")
|
|
630
|
-
xdb = xdb.assign_coords(beam_param=["major", "minor", "pa"])
|
|
631
|
-
xdb.attrs["units"] = "rad"
|
|
632
|
-
xds["beam"] = xdb
|
|
633
|
-
return xds
|
|
657
|
+
return _create_beam_data_var(xds, beam_array)
|
|
634
658
|
raise RuntimeError(
|
|
635
659
|
"It looks like there should be a BEAMS table but no "
|
|
636
660
|
"such table found in FITS file"
|
|
637
661
|
)
|
|
638
662
|
|
|
639
663
|
|
|
664
|
+
def _add_beam(xds: xr.Dataset, helpers: dict) -> xr.Dataset:
|
|
665
|
+
nchan = xds.sizes["frequency"]
|
|
666
|
+
npol = xds.sizes["polarization"]
|
|
667
|
+
beam_array = np.zeros([1, nchan, npol, 3])
|
|
668
|
+
beam_array[0, :, :, 0] = helpers["beam"]["bmaj"]["data"]
|
|
669
|
+
beam_array[0, :, :, 1] = helpers["beam"]["bmin"]["data"]
|
|
670
|
+
beam_array[0, :, :, 2] = helpers["beam"]["pa"]["data"]
|
|
671
|
+
return _create_beam_data_var(xds, beam_array)
|
|
672
|
+
|
|
673
|
+
|
|
674
|
+
def _create_beam_data_var(xds: xr.Dataset, beam_array: np.array) -> xr.Dataset:
|
|
675
|
+
xdb = xr.DataArray(
|
|
676
|
+
beam_array, dims=["time", "frequency", "polarization", "beam_param"]
|
|
677
|
+
)
|
|
678
|
+
xdb = xdb.rename("BEAM")
|
|
679
|
+
xdb = xdb.assign_coords(beam_param=["major", "minor", "pa"])
|
|
680
|
+
xdb.attrs["units"] = "rad"
|
|
681
|
+
xds["BEAM"] = xdb
|
|
682
|
+
return xds
|
|
683
|
+
|
|
684
|
+
|
|
640
685
|
def _get_uv_values(helpers: dict) -> tuple:
|
|
641
686
|
shape = helpers["shape"]
|
|
642
687
|
ctype = helpers["ctype"]
|
|
@@ -680,8 +725,8 @@ def _add_sky_or_aperture(
|
|
|
680
725
|
pp = da if type(xda[0].data) == dask.array.core.Array else np
|
|
681
726
|
mask = pp.isnan(xda)
|
|
682
727
|
mask.attrs = {}
|
|
683
|
-
mask = mask.rename("
|
|
684
|
-
xds["
|
|
728
|
+
mask = mask.rename("MASK0")
|
|
729
|
+
xds["MASK0"] = mask
|
|
685
730
|
return xds
|
|
686
731
|
|
|
687
732
|
|
|
@@ -790,10 +835,10 @@ def _get_transpose_list(helpers: dict) -> tuple:
|
|
|
790
835
|
or b.startswith("vopt")
|
|
791
836
|
or b.startswith("vrad")
|
|
792
837
|
):
|
|
793
|
-
transpose_list[
|
|
838
|
+
transpose_list[1] = i
|
|
794
839
|
not_covered.remove("f")
|
|
795
840
|
elif b.startswith("stok"):
|
|
796
|
-
transpose_list[
|
|
841
|
+
transpose_list[2] = i
|
|
797
842
|
not_covered.remove("s")
|
|
798
843
|
else:
|
|
799
844
|
raise RuntimeError(f"Unhandled axis name {c}")
|
|
@@ -12,9 +12,9 @@ from numcodecs.compat import (
|
|
|
12
12
|
ensure_contiguous_ndarray_like,
|
|
13
13
|
)
|
|
14
14
|
|
|
15
|
-
full_dims_lm = ["time", "
|
|
16
|
-
full_dims_uv = ["time", "
|
|
17
|
-
norm_dims = ["
|
|
15
|
+
full_dims_lm = ["time", "frequency", "polarization", "l", "m"]
|
|
16
|
+
full_dims_uv = ["time", "frequency", "polarization", "l", "m"]
|
|
17
|
+
norm_dims = ["frequency", "polarization"]
|
|
18
18
|
|
|
19
19
|
image_data_variables_and_dims_double_precision = {
|
|
20
20
|
"aperture": {"dims": full_dims_uv, "dtype": "<c16", "name": "APERTURE"},
|
xradio/image/_util/casacore.py
CHANGED
|
@@ -55,15 +55,16 @@ def _load_casa_image_block(infile: str, block_des: dict, do_sky_coords) -> xr.Da
|
|
|
55
55
|
block = _get_persistent_block(
|
|
56
56
|
full_path, shapes, starts, dimorder, transpose_list, new_axes
|
|
57
57
|
)
|
|
58
|
-
|
|
58
|
+
# data vars are all caps by convention
|
|
59
|
+
xds = _add_mask(xds, m.upper(), block, dimorder)
|
|
59
60
|
xds.attrs = _casa_image_to_xds_attrs(image_full_path, True)
|
|
60
61
|
mb = _multibeam_array(xds, image_full_path, False)
|
|
61
62
|
if mb is not None:
|
|
62
63
|
selectors = {}
|
|
63
|
-
for k in ("time", "
|
|
64
|
+
for k in ("time", "frequency", "polarization"):
|
|
64
65
|
if k in block_des:
|
|
65
66
|
selectors[k] = block_des[k]
|
|
66
|
-
xds["
|
|
67
|
+
xds["BEAM"] = mb.isel(selectors)
|
|
67
68
|
return xds
|
|
68
69
|
|
|
69
70
|
|
|
@@ -90,11 +91,12 @@ def _read_casa_image(
|
|
|
90
91
|
mymasks = _get_mask_names(img_full_path)
|
|
91
92
|
for m in mymasks:
|
|
92
93
|
ary = _read_image_array(img_full_path, chunks, mask=m, verbose=verbose)
|
|
93
|
-
|
|
94
|
+
# data var names are all caps by convention
|
|
95
|
+
xds = _add_mask(xds, m.upper(), ary, dimorder)
|
|
94
96
|
xds.attrs = _casa_image_to_xds_attrs(img_full_path, history)
|
|
95
97
|
mb = _multibeam_array(xds, img_full_path, True)
|
|
96
98
|
if mb is not None:
|
|
97
|
-
xds["
|
|
99
|
+
xds["BEAM"] = mb
|
|
98
100
|
# xds = _add_coord_attrs(xds, ret["icoords"], ret["dir_axes"])
|
|
99
101
|
xds = _dask_arrayize_dv(xds)
|
|
100
102
|
return xds
|
xradio/image/_util/common.py
CHANGED
|
@@ -10,7 +10,13 @@ from xradio._utils.dict_helpers import make_quantity
|
|
|
10
10
|
|
|
11
11
|
_c = 2.99792458e08 * u.m / u.s
|
|
12
12
|
# OPTICAL = Z
|
|
13
|
-
_doppler_types = [
|
|
13
|
+
_doppler_types = [
|
|
14
|
+
"radio",
|
|
15
|
+
"z",
|
|
16
|
+
"ratio",
|
|
17
|
+
"beta",
|
|
18
|
+
"gamma",
|
|
19
|
+
]
|
|
14
20
|
_image_type = "image_type"
|
|
15
21
|
|
|
16
22
|
|
|
@@ -19,7 +25,7 @@ def _aperture_or_sky(xds: xr.Dataset) -> str:
|
|
|
19
25
|
|
|
20
26
|
|
|
21
27
|
def _get_xds_dim_order(has_sph: bool) -> list:
|
|
22
|
-
dimorder = ["time", "
|
|
28
|
+
dimorder = ["time", "frequency", "polarization"]
|
|
23
29
|
dir_lin = ["l", "m"] if has_sph else ["u", "v"]
|
|
24
30
|
dimorder.extend(dir_lin)
|
|
25
31
|
return dimorder
|
|
@@ -34,10 +40,10 @@ def _convert_beam_to_rad(beam: dict) -> dict:
|
|
|
34
40
|
"""
|
|
35
41
|
mybeam = {}
|
|
36
42
|
for k in beam:
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
43
|
+
myu = beam[k]["attrs"]["units"]
|
|
44
|
+
myu = myu[0] if isinstance(myu, list) else myu
|
|
45
|
+
units = _get_unit(myu)
|
|
46
|
+
q = u.quantity.Quantity(f"{beam[k]['data']}{units}")
|
|
41
47
|
q = q.to("rad")
|
|
42
48
|
j = "pa" if k == "positionangle" else k
|
|
43
49
|
mybeam[j] = make_quantity(q.value, "rad")
|
|
@@ -105,7 +111,7 @@ def _default_freq_info() -> dict:
|
|
|
105
111
|
return {
|
|
106
112
|
"rest_frequency": make_quantity(1420405751.7860003, "Hz"),
|
|
107
113
|
"type": "frequency",
|
|
108
|
-
"frame": "
|
|
114
|
+
"frame": "lsrk",
|
|
109
115
|
"units": "Hz",
|
|
110
116
|
"waveUnit": "mm",
|
|
111
117
|
"cdelt": 1000.0,
|
|
@@ -253,22 +259,3 @@ def _l_m_attr_notes() -> Dict[str, str]:
|
|
|
253
259
|
"So m = y*cdelt, where y is the number of pixels from the phase center. "
|
|
254
260
|
"See AIPS Memo #27, Section III.",
|
|
255
261
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
def _set_multibeam_array(xds, beam_ary, units):
|
|
259
|
-
if "beam" in xds.attrs:
|
|
260
|
-
if xds.attrs["beam"] is None:
|
|
261
|
-
del xds.attrs["beam"]
|
|
262
|
-
else:
|
|
263
|
-
raise RuntimeError(
|
|
264
|
-
"Error: xds has beam attr. It must be removed "
|
|
265
|
-
"before multiple beams can be added"
|
|
266
|
-
)
|
|
267
|
-
xdb = xr.DataArray(
|
|
268
|
-
beam_ary, dims=["time", "polarization", "frequency", "beam_param"]
|
|
269
|
-
)
|
|
270
|
-
xdb = xdb.rename("beam")
|
|
271
|
-
xdb = xdb.assign_coords(beam_param=["major", "minor", "pa"])
|
|
272
|
-
xdb.attrs["units"] = units
|
|
273
|
-
xds["beam"] = xdb
|
|
274
|
-
return xds
|