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.
Files changed (32) hide show
  1. xradio/__init__.py +1 -0
  2. xradio/_utils/dict_helpers.py +69 -2
  3. xradio/image/_util/__init__.py +0 -3
  4. xradio/image/_util/_casacore/common.py +0 -13
  5. xradio/image/_util/_casacore/xds_from_casacore.py +102 -97
  6. xradio/image/_util/_casacore/xds_to_casacore.py +36 -24
  7. xradio/image/_util/_fits/xds_from_fits.py +81 -36
  8. xradio/image/_util/_zarr/zarr_low_level.py +3 -3
  9. xradio/image/_util/casacore.py +7 -5
  10. xradio/image/_util/common.py +13 -26
  11. xradio/image/_util/image_factory.py +143 -191
  12. xradio/image/image.py +10 -59
  13. xradio/measurement_set/__init__.py +11 -6
  14. xradio/measurement_set/_utils/_msv2/_tables/read.py +187 -46
  15. xradio/measurement_set/_utils/_msv2/_tables/table_query.py +22 -0
  16. xradio/measurement_set/_utils/_msv2/conversion.py +351 -318
  17. xradio/measurement_set/_utils/_msv2/msv4_info_dicts.py +20 -17
  18. xradio/measurement_set/convert_msv2_to_processing_set.py +46 -6
  19. xradio/measurement_set/load_processing_set.py +100 -53
  20. xradio/measurement_set/measurement_set_xdt.py +197 -0
  21. xradio/measurement_set/open_processing_set.py +122 -86
  22. xradio/measurement_set/processing_set_xdt.py +1552 -0
  23. xradio/measurement_set/schema.py +199 -94
  24. xradio/schema/bases.py +5 -1
  25. xradio/schema/check.py +97 -5
  26. {xradio-0.0.48.dist-info → xradio-0.0.49.dist-info}/METADATA +4 -4
  27. {xradio-0.0.48.dist-info → xradio-0.0.49.dist-info}/RECORD +30 -30
  28. {xradio-0.0.48.dist-info → xradio-0.0.49.dist-info}/WHEEL +1 -1
  29. xradio/measurement_set/measurement_set_xds.py +0 -117
  30. xradio/measurement_set/processing_set.py +0 -803
  31. {xradio-0.0.48.dist-info → xradio-0.0.49.dist-info/licenses}/LICENSE.txt +0 -0
  32. {xradio-0.0.48.dist-info → xradio-0.0.49.dist-info}/top_level.txt +0 -0
xradio/__init__.py CHANGED
@@ -1,6 +1,7 @@
1
1
  import os
2
2
  from toolviper.utils.logger import setup_logger
3
3
 
4
+
4
5
  # _logger_name = "xradio"
5
6
  # if os.getenv("VIPER_LOGGER_NAME") != _logger_name:
6
7
  # os.environ["VIPER_LOGGER_NAME"] = _logger_name
@@ -1,4 +1,4 @@
1
- def make_quantity(value, units: str) -> dict:
1
+ def make_quantity(value, units: str, dims: list = []) -> dict:
2
2
  """
3
3
  create a quantity dictionary given value and units
4
4
  Parameters
@@ -11,4 +11,71 @@ def make_quantity(value, units: str) -> dict:
11
11
  -------
12
12
  dict
13
13
  """
14
- return {"value": value, "units": units, "type": "quantity"}
14
+ u = units if isinstance(units, list) else [units]
15
+ return {"data": value, "dims": dims, "attrs": {"units": u, "type": "quantity"}}
16
+
17
+
18
+ def make_frequency_reference_dict(
19
+ value: float, units: str, observer: str = "lsrk"
20
+ ) -> dict:
21
+ u = units if isinstance(units, list) else [units]
22
+ return {
23
+ "attrs": {"units": u, "observer": observer.lower(), "type": "frequency"},
24
+ "data": value,
25
+ "dims": [],
26
+ }
27
+
28
+
29
+ def make_skycoord_dict(data: list[float], units: list[str], frame: str) -> dict:
30
+ return {
31
+ "attrs": {
32
+ "frame": frame.lower(),
33
+ "type": "sky_coord",
34
+ "units": units,
35
+ },
36
+ "data": data,
37
+ "dims": ["l", "m"],
38
+ }
39
+
40
+
41
+ def make_time_measure_attrs(units=["s"], scale="utc", time_format="mjd") -> dict:
42
+ u = units if isinstance(units, list) else [units]
43
+ return {"units": u, "scale": scale, "format": time_format, "type": "time"}
44
+
45
+
46
+ def make_time_coord_attrs(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 = make_time_measure_attrs(units, scale, time_format)
64
+ del x["type"]
65
+ return x
66
+
67
+
68
+ def _casacore_q_to_xradio_q(q: dict) -> dict:
69
+ """
70
+ Convert a casacore quantity to an xradio quantity
71
+ """
72
+ if isinstance(q, dict):
73
+ if "value" in q and "unit" in q:
74
+ return make_quantity(q["value"], q["unit"])
75
+ else:
76
+ p = {}
77
+ for k in q:
78
+ p[k] = _casacore_q_to_xradio_q(q[k])
79
+ return p
80
+ else:
81
+ raise ValueError(f"Cannot convert {q} to xradio quantity")
@@ -1,3 +0,0 @@
1
- from .common import _set_multibeam_array
2
-
3
- __all__ = ["_set_multibeam_array"]
@@ -15,19 +15,6 @@ def _open_image_ro(infile: str) -> Generator[images.image, None, None]:
15
15
  del image
16
16
 
17
17
 
18
- """
19
- @contextmanager
20
- def _open_image_rw(
21
- infile: str, mask: str, shape: tuple
22
- ) -> Generator[images.image, None, None]:
23
- image = images.image(infile, maskname=mask, shape=shape)
24
- try:
25
- yield image
26
- finally:
27
- del image
28
- """
29
-
30
-
31
18
  @contextmanager
32
19
  def _create_new_image(
33
20
  outfile: str, shape: List[int], mask="", value="default"
@@ -31,16 +31,12 @@ from ..common import (
31
31
  )
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
- from xradio._utils.dict_helpers import make_quantity
35
-
36
- """
37
- def _add_coord_attrs(xds: xr.Dataset, icoords: dict, dir_axes: list) -> xr.Dataset:
38
- _add_time_attrs(xds, icoords)
39
- _add_freq_attrs(xds, icoords)
40
- xds = _add_vel_attrs(xds, icoords)
41
- xds = _add_lin_attrs(xds, icoords, dir_axes)
42
- return xds
43
- """
34
+ from xradio._utils.dict_helpers import (
35
+ make_quantity,
36
+ make_frequency_reference_dict,
37
+ make_skycoord_dict,
38
+ _casacore_q_to_xradio_q,
39
+ )
44
40
 
45
41
 
46
42
  def _add_lin_attrs(xds, coord_dict, dir_axes):
@@ -65,11 +61,16 @@ def _add_freq_attrs(xds, coord_dict):
65
61
  sd = coord_dict[k]
66
62
  meta["rest_frequency"] = make_quantity(sd["restfreq"], "Hz")
67
63
  meta["type"] = "frequency"
68
- meta["units"] = sd["unit"]
69
- meta["frame"] = sd["system"]
64
+ # meta["units"] = sd["unit"]
65
+ # meta["frame"] = sd["system"]
70
66
  meta["wave_unit"] = sd["waveUnit"]
71
- meta["crval"] = sd["wcs"]["crval"]
72
- meta["cdelt"] = sd["wcs"]["cdelt"]
67
+ # meta["crval"] = sd["wcs"]["crval"]
68
+ # meta["cdelt"] = sd["wcs"]["cdelt"]
69
+ meta["reference_value"] = make_frequency_reference_dict(
70
+ value=sd["wcs"]["crval"],
71
+ units=sd["unit"],
72
+ observer=sd["system"],
73
+ )
73
74
  if not meta:
74
75
  # this is the default frequency information CASA creates
75
76
  meta = _default_freq_info()
@@ -108,7 +109,7 @@ def _add_sky_or_aperture(
108
109
 
109
110
 
110
111
  def _get_time_format(value: float, unit: str) -> str:
111
- if value >= 40000 and value <= 100000 and unit == "d":
112
+ if value >= 40000 and value <= 100000 and (unit == "d" or unit == ["d"]):
112
113
  return "MJD"
113
114
  else:
114
115
  return ""
@@ -119,7 +120,7 @@ def _add_time_attrs(xds: xr.Dataset, coord_dict: dict) -> xr.Dataset:
119
120
  meta = {}
120
121
  meta["type"] = "time"
121
122
  meta["scale"] = coord_dict["obsdate"]["refer"]
122
- meta["units"] = coord_dict["obsdate"]["m0"]["unit"]
123
+ meta["units"] = [coord_dict["obsdate"]["m0"]["unit"]]
123
124
  meta["format"] = _get_time_format(xds["time"][0], meta["units"])
124
125
  xds["time"].attrs = copy.deepcopy(meta)
125
126
  # xds['time'] = time_coord
@@ -128,7 +129,7 @@ def _add_time_attrs(xds: xr.Dataset, coord_dict: dict) -> xr.Dataset:
128
129
 
129
130
  def _add_vel_attrs(xds: xr.Dataset, coord_dict: dict) -> xr.Dataset:
130
131
  vel_coord = xds["velocity"]
131
- meta = {"units": "m/s"}
132
+ meta = {"units": ["m/s"]}
132
133
  for k in coord_dict:
133
134
  if k.startswith("spectral"):
134
135
  sd = coord_dict[k]
@@ -164,22 +165,24 @@ def _casa_image_to_xds_attrs(img_full_path: str, history: bool = True) -> dict:
164
165
  casa_system = coord_dir_dict[system]
165
166
  ap_system, ap_equinox = _convert_direction_system(casa_system, "native")
166
167
  dir_dict = {}
167
- dir_dict["reference"] = {
168
- "frame": ap_system,
169
- "type": "sky_coord",
170
- "equinox": ap_equinox if ap_equinox else None,
171
- "value": [0.0, 0.0],
172
- "units": ["rad", "rad"],
173
- }
168
+
169
+ dir_dict["reference"] = make_skycoord_dict(
170
+ data=[0.0, 0.0], units=["rad", "rad"], frame=ap_system
171
+ )
172
+ if ap_equinox:
173
+ dir_dict["reference"]["attrs"]["equinox"] = ap_equinox
174
174
  for i in range(2):
175
175
  unit = u.Unit(_get_unit(coord_dir_dict["units"][i]))
176
176
  q = coord_dir_dict["crval"][i] * unit
177
177
  x = q.to("rad")
178
- dir_dict["reference"]["value"][i] = x.value
178
+ dir_dict["reference"]["data"][i] = x.value
179
179
  k = "latpole"
180
180
  if k in coord_dir_dict:
181
- for j in (k, "longpole"):
182
- dir_dict[j] = make_quantity(coord_dir_dict[j] * _deg_to_rad, "rad")
181
+ for j in (k, "lonpole"):
182
+ m = "longpole" if j == "lonpole" else j
183
+ dir_dict[j] = make_quantity(
184
+ value=coord_dir_dict[m] * _deg_to_rad, units="rad", dims=["l", "m"]
185
+ )
183
186
  for j in ("pc", "projection_parameters", "projection"):
184
187
  if j in coord_dir_dict:
185
188
  dir_dict[j] = coord_dir_dict[j]
@@ -216,7 +219,8 @@ def _casa_image_to_xds_attrs(img_full_path: str, history: bool = True) -> dict:
216
219
  )
217
220
  elif k == "obsdate":
218
221
  obsdate["scale"] = coord_dict[k]["refer"]
219
- obsdate["units"] = coord_dict[k]["m0"]["unit"]
222
+ myu = coord_dict[k]["m0"]["unit"]
223
+ obsdate["units"] = myu if isinstance(myu, list) else [myu]
220
224
  obsdate["value"] = coord_dict[k]["m0"]["value"]
221
225
  obsdate["format"] = _get_time_format(obsdate["value"], obsdate["units"])
222
226
  obsdate["type"] = "time"
@@ -225,12 +229,12 @@ def _casa_image_to_xds_attrs(img_full_path: str, history: bool = True) -> dict:
225
229
  imageinfo = meta_dict["imageinfo"]
226
230
  obj = "objectname"
227
231
  attrs[_object_name] = imageinfo[obj] if obj in imageinfo else ""
228
- attrs["beam"] = _get_beam(imageinfo)
229
232
  attrs["user"] = meta_dict["miscinfo"]
230
233
  defmask = "Image_defaultmask"
231
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
232
236
  attrs[_active_mask] = (
233
- casa_table.getkeyword(defmask)
237
+ casa_table.getkeyword(defmask).upper()
234
238
  if defmask in casa_table.keywordnames()
235
239
  else None
236
240
  )
@@ -280,15 +284,15 @@ def _casa_image_to_xds_coords(
280
284
  coords = {}
281
285
  coord_attrs = {}
282
286
  (coords["time"], coord_attrs["time"]) = _get_time_values_attrs(coord_dict)
283
- (coords["polarization"], coord_attrs["polarization"]) = _get_pol_values_attrs(
284
- coord_dict
285
- )
286
287
  (coords["frequency"], coord_attrs["frequency"]) = _get_freq_values_attrs(
287
288
  csys, shape
288
289
  )
289
290
  (velocity_vals, coord_attrs["velocity"]) = _get_velocity_values_attrs(
290
291
  coord_dict, coords["frequency"]
291
292
  )
293
+ (coords["polarization"], coord_attrs["polarization"]) = _get_pol_values_attrs(
294
+ coord_dict
295
+ )
292
296
  coords["velocity"] = (["frequency"], velocity_vals)
293
297
  if len(sphr_dims) > 0:
294
298
  crpix = _flatten_list(csys.get_referencepixel())[::-1]
@@ -302,10 +306,6 @@ def _casa_image_to_xds_coords(
302
306
  naxis=shape[idx], crval=0.0, crpix=crpix[idx], cdelt=delta
303
307
  )
304
308
  coord_attrs[c] = {
305
- "crval": 0.0,
306
- "cdelt": delta,
307
- "units": "rad",
308
- "type": "quantity",
309
309
  "note": attr_note[c],
310
310
  }
311
311
  if do_sky_coords:
@@ -333,6 +333,7 @@ def _casa_image_to_xds_coords(
333
333
  ret = _get_uv_values_attrs(coord_dict, axis_names, shape)
334
334
  for z in ["u", "v"]:
335
335
  coords[z], coord_attrs[z] = ret[z]
336
+ coords["beam_param"] = ["major", "minor", "pa"]
336
337
  attrs["shape"] = shape
337
338
  xds = xr.Dataset(coords=coords)
338
339
  for c in coord_attrs.keys():
@@ -348,18 +349,18 @@ def _convert_direction_system(
348
349
  if verbose:
349
350
  logger.info(
350
351
  f"J2000 found as {which} reference frame in CASA image "
351
- 'This corresponds to FK5(equinox="J2000") in astropy. '
352
+ 'This corresponds to fk5(equinox="j2000") in astropy. '
352
353
  "Metadata will be written appropriately"
353
354
  )
354
- return ("FK5", "J2000.0")
355
+ return ("fk5", "j2000.0")
355
356
  elif casa_system == "B1950":
356
357
  if verbose:
357
358
  logger.info(
358
359
  f"B1950 found as {which} reference frame in CASA image "
359
- 'This corresponds to FK4(equinox="B1950") in astropy. '
360
+ 'This corresponds to fk4(equinox="b1950") in astropy. '
360
361
  "Metadata will be written appropriately"
361
362
  )
362
- return ("FK4", "B1950.0")
363
+ return ("fk4", "b1950.0")
363
364
  elif casa_system in ("GALACTIC", "ICRS"):
364
365
  return (casa_system.lower(), None)
365
366
  else:
@@ -382,14 +383,6 @@ def _flatten_list(list_of_lists: list) -> list:
382
383
  return flat
383
384
 
384
385
 
385
- def _get_beam(imageinfo: dict):
386
- """Returns None if no beam. Multiple beams are handled elsewhere"""
387
- k = "restoringbeam"
388
- if k in imageinfo and "major" in imageinfo[k]:
389
- return _convert_beam_to_rad(imageinfo[k])
390
- return None
391
-
392
-
393
386
  def _get_chunk_list(
394
387
  chunks: dict, coords: list, image_shape: Union[list, tuple]
395
388
  ) -> tuple:
@@ -510,12 +503,19 @@ def _get_freq_values_attrs(
510
503
  cdelt=wcs["cdelt"],
511
504
  )
512
505
  attrs["rest_frequency"] = make_quantity(sd["restfreq"], "Hz")
513
- attrs["type"] = "frequency"
514
- attrs["units"] = sd["unit"]
515
- attrs["frame"] = sd["system"]
506
+ # attrs["type"] = "frequency"
507
+ # attrs["units"] = sd["unit"]
508
+ # attrs["frame"] = sd["system"]
516
509
  attrs["wave_unit"] = sd["waveUnit"]
517
- attrs["crval"] = sd["wcs"]["crval"]
518
- attrs["cdelt"] = sd["wcs"]["cdelt"]
510
+ # attrs["crval"] = sd["wcs"]["crval"]
511
+ # attrs["cdelt"] = sd["wcs"]["cdelt"]
512
+
513
+ attrs["reference_value"] = make_frequency_reference_dict(
514
+ value=sd["wcs"]["crval"],
515
+ units=sd["unit"],
516
+ observer=sd["system"],
517
+ )
518
+
519
519
  attrs = copy.deepcopy(attrs)
520
520
  break
521
521
  else:
@@ -576,23 +576,33 @@ def _get_mask_names(infile: str) -> list:
576
576
  return mymasks
577
577
 
578
578
 
579
- def _get_multibeam(imageinfo: dict) -> Union[np.ndarray, None]:
580
- """Returns None if the image does not have multiple (per-plane) beams"""
581
- p = "perplanebeams"
582
- if p not in imageinfo:
579
+ def _get_beam(imageinfo: dict, nchan: int, npol: int) -> Union[np.ndarray, None]:
580
+ """Returns None if the image has no beam(s)"""
581
+ x = ["perplanebeams", "restoringbeam"]
582
+ r = None
583
+ for z in x:
584
+ if z in imageinfo:
585
+ r = z
586
+ break
587
+ if r is None:
583
588
  return None
584
- beam = imageinfo[p]
585
- nchan = beam["nChannels"]
586
- npol = beam["nStokes"]
587
- beam_array = np.zeros([1, npol, nchan, 3])
588
- for c in range(nchan):
589
- for p in range(npol):
590
- k = nchan * p + c
591
- b = beam["*" + str(k)]
592
- beam_dict = _convert_beam_to_rad(b)
593
- beam_array[0][p][c][0] = beam_dict["major"]["value"]
594
- beam_array[0][p][c][1] = beam_dict["minor"]["value"]
595
- beam_array[0][p][c][2] = beam_dict["pa"]["value"]
589
+ beam = imageinfo[r]
590
+ beam_array = np.zeros([1, nchan, npol, 3])
591
+ if r == "perplanebeams":
592
+ for c in range(nchan):
593
+ for p in range(npol):
594
+ k = nchan * p + c
595
+ b = _casacore_q_to_xradio_q(beam["*" + str(k)])
596
+ beam_dict = _convert_beam_to_rad(b)
597
+ beam_array[0][c][p][0] = beam_dict["major"]["data"]
598
+ beam_array[0][c][p][1] = beam_dict["minor"]["data"]
599
+ beam_array[0][c][p][2] = beam_dict["pa"]["data"]
600
+ elif r == "restoringbeam":
601
+ b = _casacore_q_to_xradio_q(beam)
602
+ beam_dict = _convert_beam_to_rad(b)
603
+ beam_array[0, :, :, 0] = beam_dict["major"]["data"]
604
+ beam_array[0, :, :, 1] = beam_dict["minor"]["data"]
605
+ beam_array[0, :, :, 2] = beam_dict["pa"]["data"]
596
606
  return beam_array
597
607
 
598
608
 
@@ -661,7 +671,7 @@ def _get_time_values_attrs(cimage_coord_dict: dict) -> Tuple[List[float], dict]:
661
671
  attrs["type"] = "time"
662
672
  attrs["scale"] = cimage_coord_dict["obsdate"]["refer"]
663
673
  unit = cimage_coord_dict["obsdate"]["m0"]["unit"]
664
- attrs["units"] = unit
674
+ attrs["units"] = unit if isinstance(unit, list) else [unit]
665
675
  time_val = cimage_coord_dict["obsdate"]["m0"]["value"]
666
676
  attrs["format"] = _get_time_format(time_val, unit)
667
677
  return ([time_val], copy.deepcopy(attrs))
@@ -694,15 +704,15 @@ def _get_transpose_list(coords: coordinates.coordinatesystem) -> list:
694
704
  not_covered.remove("v")
695
705
  elif b.startswith("frequency"):
696
706
  # transpose_list[2] = csys['pixelmap1'][0]
697
- transpose_list[2] = i
707
+ transpose_list[1] = i
698
708
  not_covered.remove("f")
699
709
  elif b.startswith("stok"):
700
- transpose_list[1] = i
710
+ transpose_list[2] = i
701
711
  # transpose_list[1] = csys['pixelmap2'][0]
702
712
  not_covered.remove("s")
703
713
  else:
704
714
  raise Exception(f"Unhandled axis name {c}")
705
- h = {"l": 3, "m": 4, "u": 3, "v": 4, "f": 2, "s": 1}
715
+ h = {"l": 3, "m": 4, "u": 3, "v": 4, "f": 1, "s": 2}
706
716
  for p in not_covered:
707
717
  transpose_list[h[p]] = last_axis
708
718
  new_axes.append(last_axis)
@@ -773,7 +783,7 @@ def _get_velocity_values(coord_dict: dict, freq_values: list) -> list:
773
783
  restfreq = coord_dict[k]["restfreq"]
774
784
  break
775
785
  return _compute_velocity_values(
776
- restfreq=restfreq, freq_values=freq_values, doppler="RADIO"
786
+ restfreq=restfreq, freq_values=freq_values, doppler="radio"
777
787
  )
778
788
 
779
789
 
@@ -791,11 +801,11 @@ def _get_velocity_values_attrs(
791
801
  if not attrs:
792
802
  attrs["doppler_type"] = _doppler_types[0]
793
803
 
794
- attrs["units"] = "m/s"
804
+ attrs["units"] = ["m/s"]
795
805
  attrs["type"] = "doppler"
796
806
  return (
797
807
  _compute_velocity_values(
798
- restfreq=restfreq, freq_values=freq_values, doppler="RADIO"
808
+ restfreq=restfreq, freq_values=freq_values, doppler="radio"
799
809
  ),
800
810
  copy.deepcopy(attrs),
801
811
  )
@@ -804,25 +814,20 @@ def _get_velocity_values_attrs(
804
814
  def _multibeam_array(
805
815
  xds: xr.Dataset, img_full_path: str, as_dask_array: bool
806
816
  ) -> Union[xr.DataArray, None]:
807
- """This should only be called after the xds.beam attr has been set"""
808
- if xds.attrs["beam"] is None:
809
- # the image may have multiple beams
810
- with _open_image_ro(img_full_path) as casa_image:
811
- imageinfo = casa_image.info()["imageinfo"]
812
- mb = _get_multibeam(imageinfo)
813
- if mb is not None:
814
- # multiple beams are stored as a data varialbe, so remove
815
- # the beam xds attr
816
- del xds.attrs["beam"]
817
- if as_dask_array:
818
- mb = da.array(mb)
819
- xdb = xr.DataArray(
820
- mb, dims=["time", "polarization", "frequency", "beam_param"]
821
- )
822
- xdb = xdb.rename("beam")
823
- xdb = xdb.assign_coords(beam_param=["major", "minor", "pa"])
824
- xdb.attrs["units"] = "rad"
825
- return xdb
817
+ # the image may have multiple beams
818
+ with _open_image_ro(img_full_path) as casa_image:
819
+ imageinfo = casa_image.info()["imageinfo"]
820
+ mb = _get_beam(
821
+ imageinfo, nchan=xds.sizes["frequency"], npol=xds.sizes["polarization"]
822
+ )
823
+ if mb is not None:
824
+ if as_dask_array:
825
+ mb = da.array(mb)
826
+ xdb = xr.DataArray(mb, dims=["time", "frequency", "polarization", "beam_param"])
827
+ xdb = xdb.rename("BEAM")
828
+ xdb = xdb.assign_coords(beam_param=["major", "minor", "pa"])
829
+ xdb.attrs["units"] = "rad"
830
+ return xdb
826
831
  else:
827
832
  return None
828
833
 
@@ -1023,7 +1028,7 @@ def _read_image_array(
1023
1028
  :type blc: a type that is convertable to a list via list(blc)
1024
1029
  :param trc: top right corner, given in the axes ordering of the input image.None=>image shape - 1
1025
1030
  :type trc: a type that is convertable to a list via list(trc)
1026
- :return: Dask array in time, polarization, frequency, l, m order
1031
+ :return: Dask array in time, frequency, polarization, l, m order
1027
1032
  :rtype: dask.array
1028
1033
 
1029
1034
  """
@@ -19,19 +19,24 @@ def _compute_direction_dict(xds: xr.Dataset) -> dict:
19
19
  """
20
20
  direction = {}
21
21
  xds_dir = xds.attrs["direction"]
22
- direction["system"] = xds_dir["reference"]["equinox"]
22
+ direction["system"] = xds_dir["reference"]["attrs"]["equinox"].upper()
23
+ if direction["system"] == "J2000.0":
24
+ direction["system"] = "J2000"
23
25
  direction["projection"] = xds_dir["projection"]
24
26
  direction["projection_parameters"] = xds_dir["projection_parameters"]
25
- direction["units"] = np.array(xds_dir["reference"]["units"], dtype="<U16")
26
- direction["crval"] = np.array(xds_dir["reference"]["value"])
27
- direction["cdelt"] = np.array((xds.l.cdelt, xds.m.cdelt))
27
+ direction["units"] = np.array(xds_dir["reference"]["attrs"]["units"], dtype="<U16")
28
+ direction["crval"] = np.array(xds_dir["reference"]["data"])
29
+ direction["cdelt"] = np.array((xds.l[1] - xds.l[0], xds.m[1] - xds.m[0]))
28
30
  direction["crpix"] = _compute_sky_reference_pixel(xds)
29
31
  direction["pc"] = np.array(xds_dir["pc"])
30
32
  direction["axes"] = ["Right Ascension", "Declination"]
31
33
  direction["conversionSystem"] = direction["system"]
32
34
  for s in ["longpole", "latpole"]:
33
- # longpole, latpole are numerical values in degrees in casa images
34
- direction[s] = Angle(str(xds_dir[s]["value"]) + xds_dir[s]["units"]).deg
35
+ m = "lonpole" if s == "longpole" else s
36
+ # lonpole, latpole are numerical values in degrees in casa images
37
+ direction[s] = Angle(
38
+ str(xds_dir[m]["data"]) + xds_dir[m]["attrs"]["units"][0]
39
+ ).deg
35
40
  return direction
36
41
 
37
42
 
@@ -69,20 +74,22 @@ def _compute_spectral_dict(xds: xr.Dataset) -> dict:
69
74
  # spec["nativeType"] = _native_types.index(xds.frequency.attrs["native_type"])
70
75
  # FREQ
71
76
  spec["nativeType"] = 0
72
- spec["restfreq"] = xds.frequency.attrs["rest_frequency"]["value"]
77
+ spec["restfreq"] = xds.frequency.attrs["rest_frequency"]["data"]
73
78
  # spec["restfreqs"] = copy.deepcopy(xds.frequency.attrs["restfreqs"]["value"])
74
79
  spec["restfreqs"] = [spec["restfreq"]]
75
- spec["system"] = xds.frequency.attrs["frame"]
76
- spec["unit"] = xds.frequency.attrs["units"]
80
+ spec["system"] = xds.frequency.attrs["reference_value"]["attrs"]["observer"].upper()
81
+ u = xds.frequency.attrs["reference_value"]["attrs"]["units"]
82
+ spec["unit"] = u if isinstance(u, str) else u[0]
77
83
  spec["velType"] = _doppler_types.index(xds.velocity.attrs["doppler_type"])
78
- spec["velUnit"] = xds.velocity.attrs["units"]
84
+ u = xds.velocity.attrs["units"]
85
+ spec["velUnit"] = u if isinstance(u, str) else u[0]
79
86
  spec["version"] = 2
80
87
  spec["waveUnit"] = xds.frequency.attrs["wave_unit"]
81
88
  wcs = {}
82
89
  wcs["ctype"] = "FREQ"
83
90
  wcs["pc"] = 1.0
84
- wcs["crval"] = xds.frequency.attrs["crval"]
85
- wcs["cdelt"] = xds.frequency.attrs["cdelt"]
91
+ wcs["crval"] = xds.frequency.attrs["reference_value"]["data"]
92
+ wcs["cdelt"] = xds.frequency.values[1] - xds.frequency.values[0]
86
93
  wcs["crpix"] = (wcs["crval"] - xds.frequency.values[0]) / wcs["cdelt"]
87
94
  spec["wcs"] = wcs
88
95
  return spec
@@ -96,7 +103,7 @@ def _coord_dict_from_xds(xds: xr.Dataset) -> dict:
96
103
  obsdate["refer"] = xds.coords["time"].attrs["scale"]
97
104
  obsdate["type"] = "epoch"
98
105
  obsdate["m0"] = {}
99
- obsdate["m0"]["unit"] = xds.coords["time"].attrs["units"]
106
+ obsdate["m0"]["unit"] = xds.coords["time"].attrs["units"][0]
100
107
  obsdate["m0"]["value"] = xds.coords["time"].values[0]
101
108
  coord["obsdate"] = obsdate
102
109
  coord["pointingcenter"] = xds.attrs[_pointing_center].copy()
@@ -137,7 +144,8 @@ def _coord_dict_from_xds(xds: xr.Dataset) -> dict:
137
144
  # this probbably needs some verification
138
145
  coord["worldreplace0"] = [0.0, 0.0]
139
146
  coord["worldreplace1"] = np.array(coord["stokes1"]["crval"])
140
- coord["worldreplace2"] = np.array([xds.frequency.attrs["crval"]])
147
+ # print("spectral", coord["spectral2"])
148
+ coord["worldreplace2"] = np.array(coord["spectral2"]["wcs"]["crval"])
141
149
  return coord
142
150
 
143
151
 
@@ -174,17 +182,17 @@ def _imageinfo_dict_from_xds(xds: xr.Dataset) -> dict:
174
182
  xds[ap_sky].attrs["image_type"] if "image_type" in xds[ap_sky].attrs else ""
175
183
  )
176
184
  ii["objectname"] = xds.attrs[_object_name]
177
- if "beam" in xds.data_vars:
185
+ if "BEAM" in xds.data_vars:
178
186
  # multi beam
179
187
  pp = {}
180
- pp["nChannels"] = len(xds.frequency)
181
- pp["nStokes"] = len(xds.polarization)
182
- bu = xds.beam.attrs["units"]
188
+ pp["nChannels"] = xds.sizes["frequency"]
189
+ pp["nStokes"] = xds.sizes["polarization"]
190
+ bu = xds.BEAM.attrs["units"]
183
191
  chan = 0
184
192
  polarization = 0
185
- bv = xds.beam.values
193
+ bv = xds.BEAM.values
186
194
  for i in range(pp["nChannels"] * pp["nStokes"]):
187
- bp = bv[0][polarization][chan][:]
195
+ bp = bv[0][chan][polarization][:]
188
196
  b = {
189
197
  "major": {"unit": bu, "value": bp[0]},
190
198
  "minor": {"unit": bu, "value": bp[1]},
@@ -196,15 +204,20 @@ def _imageinfo_dict_from_xds(xds: xr.Dataset) -> dict:
196
204
  chan = 0
197
205
  polarization += 1
198
206
  ii["perplanebeams"] = pp
207
+ """
199
208
  elif "beam" in xds.attrs and xds.attrs["beam"]:
200
209
  # do nothing if xds.attrs['beam'] is None
201
210
  ii["restoringbeam"] = copy.deepcopy(xds.attrs["beam"])
202
211
  for k in ["major", "minor", "pa"]:
203
- del ii["restoringbeam"][k]["type"]
204
- ii["restoringbeam"][k]["unit"] = ii["restoringbeam"][k]["units"]
205
- del ii["restoringbeam"][k]["units"]
212
+ # print("*** ", k, ii["restoringbeam"][k])
213
+ del ii["restoringbeam"][k]["dims"]
214
+ ii["restoringbeam"][k]["unit"] = ii["restoringbeam"][k]["attrs"]["units"][0]
215
+ del ii["restoringbeam"][k]["attrs"]
216
+ ii["restoringbeam"][k]["value"] = ii["restoringbeam"][k]["data"]
217
+ del ii["restoringbeam"][k]["data"]
206
218
  ii["restoringbeam"]["positionangle"] = copy.deepcopy(ii["restoringbeam"]["pa"])
207
219
  del ii["restoringbeam"]["pa"]
220
+ """
208
221
  return ii
209
222
 
210
223
 
@@ -319,7 +332,6 @@ def _write_initial_image(
319
332
  if xds[dv][0, 0, 0, 0, 0].values.dtype == "float32":
320
333
  value = "default"
321
334
  break
322
- # print(type(value))
323
335
  image_full_path = os.path.expanduser(imagename)
324
336
  with _create_new_image(
325
337
  image_full_path, mask=maskname, shape=image_shape, value=value