xradio 0.0.56__py3-none-any.whl → 0.0.59__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 (63) hide show
  1. xradio/__init__.py +2 -2
  2. xradio/_utils/_casacore/casacore_from_casatools.py +12 -2
  3. xradio/_utils/_casacore/tables.py +1 -0
  4. xradio/_utils/coord_math.py +22 -23
  5. xradio/_utils/dict_helpers.py +76 -11
  6. xradio/_utils/schema.py +5 -2
  7. xradio/_utils/zarr/common.py +1 -73
  8. xradio/image/_util/_casacore/xds_from_casacore.py +49 -33
  9. xradio/image/_util/_casacore/xds_to_casacore.py +41 -14
  10. xradio/image/_util/_fits/xds_from_fits.py +146 -35
  11. xradio/image/_util/casacore.py +4 -3
  12. xradio/image/_util/common.py +4 -4
  13. xradio/image/_util/image_factory.py +8 -8
  14. xradio/image/image.py +45 -5
  15. xradio/measurement_set/__init__.py +19 -9
  16. xradio/measurement_set/_utils/__init__.py +1 -3
  17. xradio/measurement_set/_utils/_msv2/__init__.py +0 -0
  18. xradio/measurement_set/_utils/_msv2/_tables/read.py +17 -76
  19. xradio/measurement_set/_utils/_msv2/_tables/read_main_table.py +2 -685
  20. xradio/measurement_set/_utils/_msv2/conversion.py +174 -156
  21. xradio/measurement_set/_utils/_msv2/create_antenna_xds.py +9 -16
  22. xradio/measurement_set/_utils/_msv2/create_field_and_source_xds.py +128 -222
  23. xradio/measurement_set/_utils/_msv2/msv2_to_msv4_meta.py +1 -2
  24. xradio/measurement_set/_utils/_msv2/msv4_info_dicts.py +8 -7
  25. xradio/measurement_set/_utils/_msv2/msv4_sub_xdss.py +31 -74
  26. xradio/measurement_set/_utils/_msv2/partition_queries.py +1 -261
  27. xradio/measurement_set/_utils/_msv2/subtables.py +0 -107
  28. xradio/measurement_set/_utils/_utils/interpolate.py +60 -0
  29. xradio/measurement_set/_utils/_zarr/encoding.py +2 -7
  30. xradio/measurement_set/convert_msv2_to_processing_set.py +0 -2
  31. xradio/measurement_set/load_processing_set.py +2 -2
  32. xradio/measurement_set/measurement_set_xdt.py +20 -16
  33. xradio/measurement_set/open_processing_set.py +1 -3
  34. xradio/measurement_set/processing_set_xdt.py +54 -841
  35. xradio/measurement_set/schema.py +122 -132
  36. xradio/schema/check.py +95 -101
  37. xradio/schema/dataclass.py +159 -22
  38. xradio/schema/export.py +99 -0
  39. xradio/schema/metamodel.py +51 -16
  40. xradio/schema/typing.py +5 -5
  41. xradio/sphinx/schema_table.py +41 -77
  42. {xradio-0.0.56.dist-info → xradio-0.0.59.dist-info}/METADATA +20 -5
  43. xradio-0.0.59.dist-info/RECORD +65 -0
  44. {xradio-0.0.56.dist-info → xradio-0.0.59.dist-info}/WHEEL +1 -1
  45. xradio/image/_util/fits.py +0 -13
  46. xradio/measurement_set/_utils/_msv2/_tables/load.py +0 -66
  47. xradio/measurement_set/_utils/_msv2/_tables/load_main_table.py +0 -490
  48. xradio/measurement_set/_utils/_msv2/_tables/read_subtables.py +0 -398
  49. xradio/measurement_set/_utils/_msv2/_tables/write.py +0 -323
  50. xradio/measurement_set/_utils/_msv2/_tables/write_exp_api.py +0 -388
  51. xradio/measurement_set/_utils/_msv2/chunks.py +0 -115
  52. xradio/measurement_set/_utils/_msv2/descr.py +0 -165
  53. xradio/measurement_set/_utils/_msv2/msv2_msv3.py +0 -7
  54. xradio/measurement_set/_utils/_msv2/partitions.py +0 -392
  55. xradio/measurement_set/_utils/_utils/cds.py +0 -40
  56. xradio/measurement_set/_utils/_utils/xds_helper.py +0 -404
  57. xradio/measurement_set/_utils/_zarr/read.py +0 -263
  58. xradio/measurement_set/_utils/_zarr/write.py +0 -329
  59. xradio/measurement_set/_utils/msv2.py +0 -106
  60. xradio/measurement_set/_utils/zarr.py +0 -133
  61. xradio-0.0.56.dist-info/RECORD +0 -78
  62. {xradio-0.0.56.dist-info → xradio-0.0.59.dist-info}/licenses/LICENSE.txt +0 -0
  63. {xradio-0.0.56.dist-info → xradio-0.0.59.dist-info}/top_level.txt +0 -0
xradio/__init__.py CHANGED
@@ -1,5 +1,5 @@
1
- import os
2
- from toolviper.utils.logger import setup_logger
1
+ # import os
2
+ # from toolviper.utils.logger import setup_logger
3
3
 
4
4
 
5
5
  # _logger_name = "xradio"
@@ -18,7 +18,17 @@ from typing import Any, Dict, List, Sequence, Union
18
18
  # Configure casaconfig settings prior to casatools import
19
19
  # this ensures optimal initialization and resource allocation for casatools
20
20
  # Also see : https://casadocs.readthedocs.io/en/stable/api/casaconfig.html
21
- import casaconfig.config
21
+ try:
22
+ import casaconfig.config
23
+ except ModuleNotFoundError as exc:
24
+ raise ModuleNotFoundError(
25
+ f"casaconfig.config cannot be found, probably because the package "
26
+ "casatools is not available. If you are here that is probably because "
27
+ "python-casacore is not available either. MSv2 related functionality "
28
+ "requires either python-casacore or casatools. Import failure details: "
29
+ f"{exc}"
30
+ )
31
+
22
32
  import numpy as np
23
33
  import toolviper.utils.logger as logger
24
34
 
@@ -70,7 +80,7 @@ else:
70
80
  casaconfig.config.logfile = "/dev/null"
71
81
  casaconfig.config.nologfile = True
72
82
 
73
- import casatools
83
+ import casatools # noqa: E402 (because of previous config initialization)
74
84
 
75
85
  casatools.logger.setglobal(True)
76
86
  casatools.logger.ompSetNumThreads(1)
@@ -4,6 +4,7 @@ except ImportError:
4
4
  import xradio._utils._casacore.casacore_from_casatools as tables
5
5
 
6
6
  from contextlib import contextmanager
7
+ import os
7
8
  from typing import Dict, Generator
8
9
 
9
10
  # common casacore table handling code
@@ -63,38 +63,37 @@ def wrap_to_pi(angles):
63
63
  return (angles + np.pi) % (2 * np.pi) - np.pi
64
64
 
65
65
 
66
- def wrap_to_pi(angles):
67
- return (angles + np.pi) % (2 * np.pi) - np.pi
66
+ def convert_to_si_units(xds):
67
+ import xarray as xr
68
68
 
69
+ with xr.set_options(keep_attrs=True):
70
+ for data_var in xds.data_vars:
71
+ if "units" in xds[data_var].attrs:
72
+ u = xds[data_var].attrs["units"]
69
73
 
70
- def convert_to_si_units(xds):
71
- for data_var in xds.data_vars:
72
- if "units" in xds[data_var].attrs:
73
- for u_i, u in enumerate(xds[data_var].attrs["units"]):
74
74
  if u == "km":
75
- xds[data_var][..., u_i] = xds[data_var][..., u_i] * 1e3
76
- xds[data_var].attrs["units"][u_i] = "m"
75
+ xds[data_var] = xds[data_var] * 1e3
76
+ xds[data_var].attrs["units"] = "m"
77
77
  if u == "km/s":
78
- xds[data_var][..., u_i] = xds[data_var][..., u_i] * 1e3
79
- xds[data_var].attrs["units"][u_i] = "m/s"
78
+ xds[data_var] = xds[data_var] * 1e3
79
+ xds[data_var].attrs["units"] = "m/s"
80
80
  if u == "deg":
81
- xds[data_var][..., u_i] = xds[data_var][..., u_i] * np.pi / 180
82
- xds[data_var].attrs["units"][u_i] = "rad"
81
+ xds[data_var] = xds[data_var] * np.pi / 180
82
+ xds[data_var].attrs["units"] = "rad"
83
83
  if u == "Au" or u == "AU":
84
- xds[data_var][..., u_i] = xds[data_var][..., u_i] * 149597870700
85
- xds[data_var].attrs["units"][u_i] = "m"
84
+ xds[data_var] = xds[data_var] * 149597870700
85
+ xds[data_var].attrs["units"] = "m"
86
86
  if u == "Au/d" or u == "AU/d":
87
- xds[data_var][..., u_i] = (
88
- xds[data_var][..., u_i] * 149597870700 / 86400
89
- )
90
- xds[data_var].attrs["units"][u_i] = "m/s"
87
+ xds[data_var] = xds[data_var] * 149597870700 / 86400
88
+ xds[data_var].attrs["units"] = "m/s"
91
89
  if u == "arcsec":
92
- xds[data_var][..., u_i] = xds[data_var][..., u_i] * np.pi / 648000
93
- xds[data_var].attrs["units"][u_i] = "rad"
90
+ xds[data_var] = xds[data_var] * np.pi / 648000
91
+ xds[data_var].attrs["units"] = "rad"
94
92
  if u == "hPa":
95
- xds[data_var][..., u_i] = xds[data_var][..., u_i] * 100.0
96
- xds[data_var].attrs["units"][u_i] = "Pa"
93
+ xds[data_var] = xds[data_var] * 100.0
94
+ xds[data_var].attrs["units"] = "Pa"
97
95
  if u == "m-2":
98
96
  # IONOS_ELECTRON sometimes has "m-2" instead of "/m^2"
99
- xds[data_var].attrs["units"][u_i] = "/m^2"
97
+ xds[data_var].attrs["units"] = "/m^2"
98
+
100
99
  return xds
@@ -1,49 +1,114 @@
1
1
  def make_quantity(value, units: str, dims: list = []) -> dict:
2
2
  """
3
3
  create a quantity dictionary given value and units
4
+
4
5
  Parameters
5
6
  ----------
6
7
  value : numeric or array of numerics
7
8
  Quantity value
8
9
  units: str
9
10
  Quantity units
11
+
10
12
  Returns
11
13
  -------
12
14
  dict
13
15
  """
14
- u = units if isinstance(units, list) else [units]
15
- return {"data": value, "dims": dims, "attrs": {"units": u, "type": "quantity"}}
16
+ return {"data": value, "dims": dims, "attrs": make_quantity_attrs(units)}
17
+
18
+
19
+ def ensure_units_are_consistent(units):
20
+ if isinstance(units, str):
21
+ return units
22
+ else:
23
+ u0 = units[0]
24
+ for u in units:
25
+ assert u0 == u, f"Units are not consistent: {u0} != {u}. "
26
+ return u0
16
27
 
17
28
 
18
- def make_frequency_reference_dict(
29
+ def make_quantity_attrs(units: str) -> dict:
30
+ """
31
+ Creates the dict of attributes of a quantity
32
+
33
+ Parameters
34
+ ----------
35
+ units: str
36
+ Quantity units
37
+
38
+ Returns
39
+ -------
40
+ dict
41
+ """
42
+ return {"units": ensure_units_are_consistent(units), "type": "quantity"}
43
+
44
+
45
+ def make_spectral_coord_reference_dict(
19
46
  value: float, units: str, observer: str = "lsrk"
20
47
  ) -> dict:
21
- u = units if isinstance(units, list) else [units]
48
+ """
49
+ creates a spectral_coord measure dict given the value, units, and observer
50
+
51
+ Parameters
52
+ ----------
53
+ value : numeric or array of numerics
54
+ measure value
55
+ units : str
56
+ measure units
57
+ observer :
58
+ observer reference frame
59
+
60
+ Returns
61
+ -------
62
+ dict
63
+ """
64
+ u = ensure_units_are_consistent(units)
22
65
  return {
23
- "attrs": {"units": u, "observer": observer.lower(), "type": "frequency"},
66
+ "attrs": make_spectral_coord_measure_attrs(
67
+ u,
68
+ observer.lower() if observer not in ["TOPO", "BARY", "REST"] else observer,
69
+ ),
24
70
  "data": value,
25
71
  "dims": [],
26
72
  }
27
73
 
28
74
 
29
- def make_skycoord_dict(data: list[float], units: list[str], frame: str) -> dict:
75
+ def make_spectral_coord_measure_attrs(units: str, observer: str = "lsrk") -> dict:
76
+ """
77
+ Creates a spectral_coord measure attrs dict given units and observer
78
+
79
+ Parameters
80
+ ----------
81
+ units: str or list of str
82
+ Spectral coordinate units
83
+ observer: str
84
+ Spectral reference frame
85
+ Returns
86
+ -------
87
+ dict
88
+ Attrs dict for a spectral_coord measure
89
+ """
90
+ u = ensure_units_are_consistent(units)
91
+ return {"units": u, "observer": observer, "type": "spectral_coord"}
92
+
93
+
94
+ def make_skycoord_dict(data: list[float], units: str, frame: str) -> dict:
30
95
  return {
31
96
  "attrs": {
32
97
  "frame": frame.lower(),
33
98
  "type": "sky_coord",
34
- "units": units,
99
+ "units": ensure_units_are_consistent(units),
35
100
  },
36
101
  "data": data,
37
102
  "dims": ["l", "m"],
38
103
  }
39
104
 
40
105
 
41
- def make_time_measure_attrs(units=["s"], scale="utc", time_format="mjd") -> dict:
42
- u = units if isinstance(units, list) else [units]
106
+ def make_time_measure_attrs(units="s", scale="utc", time_format="mjd") -> dict:
107
+ u = ensure_units_are_consistent(units)
43
108
  return {"units": u, "scale": scale, "format": time_format, "type": "time"}
44
109
 
45
110
 
46
- def make_time_measure_dict(data, units=["s"], scale="utc", time_format="mjd") -> dict:
111
+ def make_time_measure_dict(data, units="s", scale="utc", time_format="mjd") -> dict:
47
112
  """
48
113
  create a time measure dictionary given value and units
49
114
  Parameters
@@ -67,7 +132,7 @@ def make_time_measure_dict(data, units=["s"], scale="utc", time_format="mjd") ->
67
132
  return x
68
133
 
69
134
 
70
- def make_time_coord_attrs(units=["s"], scale="utc", time_format="mjd") -> dict:
135
+ def make_time_coord_attrs(units="s", scale="utc", time_format="mjd") -> dict:
71
136
  """
72
137
  create a time measure dictionary given value and units
73
138
  Parameters
xradio/_utils/schema.py CHANGED
@@ -1,6 +1,7 @@
1
1
  import toolviper.utils.logger as logger
2
2
  import xarray as xr
3
3
  from typing import Union
4
+ from xradio._utils.dict_helpers import ensure_units_are_consistent
4
5
 
5
6
 
6
7
  def convert_generic_xds_to_xradio_schema(
@@ -108,7 +109,7 @@ def column_description_casacore_to_msv4_measure(
108
109
 
109
110
  # Convert type, copy unit
110
111
  msv4_measure["type"] = msv4_measure_conversion["type"]
111
- msv4_measure["units"] = list(
112
+ msv4_measure["units"] = ensure_units_are_consistent(
112
113
  casacore_column_description["keywords"]["QuantumUnits"]
113
114
  )
114
115
 
@@ -154,7 +155,9 @@ def column_description_casacore_to_msv4_measure(
154
155
  elif "QuantumUnits" in casacore_column_description["keywords"]:
155
156
  msv4_measure = {
156
157
  "type": "quantity",
157
- "units": list(casacore_column_description["keywords"]["QuantumUnits"]),
158
+ "units": ensure_units_are_consistent(
159
+ casacore_column_description["keywords"]["QuantumUnits"]
160
+ ),
158
161
  }
159
162
 
160
163
  return msv4_measure
@@ -1,6 +1,4 @@
1
- import copy
2
1
  import xarray as xr
3
- import zarr
4
2
  import s3fs
5
3
  import os
6
4
  from botocore.exceptions import NoCredentialsError
@@ -34,7 +32,7 @@ def _get_file_system_and_items(ps_store: str):
34
32
  for bd in file_system.listdir(ps_store, detail=False)
35
33
  ]
36
34
 
37
- except (NoCredentialsError, PermissionError) as e:
35
+ except (NoCredentialsError, PermissionError):
38
36
  # only public, read-only buckets will be accessible
39
37
  # we will want to add messaging and error handling here
40
38
  file_system = s3fs.S3FileSystem(anon=True)
@@ -97,73 +95,3 @@ def _open_dataset(
97
95
  with dask.config.set(scheduler="synchronous"):
98
96
  xds = xds.load()
99
97
  return xds
100
-
101
-
102
- # Code to depricate:
103
- def _get_attrs(zarr_obj):
104
- """
105
- get attributes of zarr obj (groups or arrays)
106
- """
107
- return {k: v for k, v in zarr_obj.attrs.asdict().items() if not k.startswith("_NC")}
108
-
109
-
110
- def _load_no_dask_zarr(zarr_name, slice_dict={}):
111
- """
112
- Alternative to xarray open_zarr where the arrays are not Dask Arrays.
113
-
114
- slice_dict: A dictionary of slice objects for which values to read form a dimension.
115
- For example silce_dict={'time':slice(0,10)} would select the first 10 elements in the time dimension.
116
- If a dim is not specified all values are retruned.
117
- return:
118
- xarray.Dataset()
119
-
120
- #Should go into general utils.
121
- """
122
- # Used by xarray to store array labeling info in zarr meta data.
123
- DIMENSION_KEY = "_ARRAY_DIMENSIONS"
124
-
125
- # logger = _get_logger()
126
- zarr_group = zarr.open_group(store=zarr_name, mode="r")
127
- group_attrs = _get_attrs(zarr_group)
128
-
129
- slice_dict_complete = copy.deepcopy(slice_dict)
130
- coords = {}
131
- xds = xr.Dataset()
132
- for var_name, var in zarr_group.arrays():
133
- print("Hallo 3", var_name, var.shape)
134
- var_attrs = _get_attrs(var)
135
-
136
- for dim in var_attrs[DIMENSION_KEY]:
137
- if dim not in slice_dict_complete:
138
- slice_dict_complete[dim] = slice(None) # No slicing.
139
-
140
- if (var_attrs[DIMENSION_KEY][0] == var_name) and (
141
- len(var_attrs[DIMENSION_KEY]) == 1
142
- ):
143
- coord = var[
144
- slice_dict_complete[var_attrs[DIMENSION_KEY][0]]
145
- ] # Dimension coordinates.
146
- del var_attrs["_ARRAY_DIMENSIONS"]
147
- xds = xds.assign_coords({var_name: coord})
148
- xds[var_name].attrs = var_attrs
149
- else:
150
- # Construct slicing
151
- slicing_list = []
152
- for dim in var_attrs[DIMENSION_KEY]:
153
- slicing_list.append(slice_dict_complete[dim])
154
- slicing_tuple = tuple(slicing_list)
155
-
156
- print(var_attrs[DIMENSION_KEY])
157
-
158
- xds[var_name] = xr.DataArray(
159
- var[slicing_tuple], dims=var_attrs[DIMENSION_KEY]
160
- )
161
-
162
- if "coordinates" in var_attrs:
163
- del var_attrs["coordinates"]
164
- del var_attrs["_ARRAY_DIMENSIONS"]
165
- xds[var_name].attrs = var_attrs
166
-
167
- xds.attrs = group_attrs
168
-
169
- return xds
@@ -41,7 +41,7 @@ from ...._utils._casacore.tables import extract_table_attributes, open_table_ro
41
41
  from xradio._utils.coord_math import _deg_to_rad
42
42
  from xradio._utils.dict_helpers import (
43
43
  _casacore_q_to_xradio_q,
44
- make_frequency_reference_dict,
44
+ make_spectral_coord_reference_dict,
45
45
  make_quantity,
46
46
  make_skycoord_dict,
47
47
  make_time_measure_dict,
@@ -85,34 +85,50 @@ def _casa_image_to_xds_image_attrs(image: casa_image, history: bool = True) -> d
85
85
  attrs["units"] = image.unit()
86
86
  attrs["telescope"] = {}
87
87
  telescope = attrs["telescope"]
88
+
88
89
  for k in ("observer", "obsdate", "telescope", "telescopeposition"):
89
90
  if k.startswith("telescope"):
90
91
  if k == "telescope":
91
92
  telescope["name"] = coord_dict[k]
92
93
  elif k in coord_dict:
93
94
  casa_pos = coord_dict[k]
94
- location = {}
95
- loc_attrs = {}
96
- loc_attrs["type"] = "location"
97
- loc_attrs["frame"] = casa_pos["refer"]
98
- """
99
- if casa_pos["refer"] == "ITRF":
100
- loc_attrs["ellipsoid"] = "GRS80"
101
- """
102
- loc_attrs["units"] = [
103
- casa_pos["m0"]["unit"],
104
- casa_pos["m1"]["unit"],
105
- casa_pos["m2"]["unit"],
106
- ]
107
- loc_attrs["coordinate_system"] = "geocentric"
108
- loc_attrs["origin_object_name"] = "earth"
109
- location["attrs"] = loc_attrs
110
- location["data"] = [
111
- casa_pos["m0"]["value"],
112
- casa_pos["m1"]["value"],
113
- casa_pos["m2"]["value"],
114
- ]
115
- telescope["location"] = location
95
+ telescope["direction"] = {
96
+ "attrs": {
97
+ "coordinate_system": "geocentric",
98
+ "frame": casa_pos["refer"],
99
+ "origin_object_name": "earth",
100
+ "type": "location",
101
+ "units": casa_pos["m0"]["unit"],
102
+ },
103
+ "data": [casa_pos["m0"]["value"], casa_pos["m1"]["value"]],
104
+ "dims": ["ellipsoid_dir_label"],
105
+ "coords": {
106
+ "ellipsoid_dir_label": {
107
+ "dims": ["ellipsoid_dir_label"],
108
+ "data": ["lon", "lat"],
109
+ }
110
+ },
111
+ }
112
+ telescope["distance"] = {
113
+ "attrs": {
114
+ "coordinate_system": "geocentric",
115
+ "frame": casa_pos["refer"],
116
+ "origin_object_name": "earth",
117
+ "type": "location",
118
+ "units": casa_pos["m2"]["unit"],
119
+ },
120
+ "data": [casa_pos["m2"]["value"]],
121
+ "dims": ["ellipsoid_dis_label"],
122
+ "coords": {
123
+ "ellipsoid_dis_label": {
124
+ "dims": ["ellipsoid_dis_label"],
125
+ "data": [
126
+ "dist",
127
+ ],
128
+ }
129
+ },
130
+ }
131
+
116
132
  """
117
133
  del (
118
134
  telescope["position"]["refer"],
@@ -155,7 +171,7 @@ def _casa_image_to_xds_image_attrs(image: casa_image, history: bool = True) -> d
155
171
  # associated with it.
156
172
  # point_center = coord_dict["pointingcenter"]
157
173
  attrs[_pointing_center] = make_skycoord_dict(
158
- coord_dict["pointingcenter"]["value"].tolist(), ["rad", "rad"], frame
174
+ coord_dict["pointingcenter"]["value"].tolist(), "rad", frame
159
175
  )
160
176
  imageinfo = meta_dict["imageinfo"]
161
177
  obj = "objectname"
@@ -221,7 +237,7 @@ def _add_time_attrs(xds: xr.Dataset, coord_dict: dict) -> xr.Dataset:
221
237
 
222
238
  def _add_vel_attrs(xds: xr.Dataset, coord_dict: dict) -> xr.Dataset:
223
239
  vel_coord = xds["velocity"]
224
- meta = {"units": ["m/s"]}
240
+ meta = {"units": "m/s"}
225
241
  for k in coord_dict:
226
242
  if k.startswith("spectral"):
227
243
  sd = coord_dict[k]
@@ -259,7 +275,7 @@ def _casa_image_to_xds_attrs(img_full_path: str) -> dict:
259
275
  dir_dict = {}
260
276
 
261
277
  dir_dict["reference"] = make_skycoord_dict(
262
- data=[0.0, 0.0], units=["rad", "rad"], frame=ap_system
278
+ data=[0.0, 0.0], units="rad", frame=ap_system
263
279
  )
264
280
  if ap_equinox:
265
281
  dir_dict["reference"]["attrs"]["equinox"] = ap_equinox
@@ -534,14 +550,14 @@ def _get_freq_values_attrs(
534
550
  cdelt=wcs["cdelt"],
535
551
  )
536
552
  attrs["rest_frequency"] = make_quantity(sd["restfreq"], "Hz")
537
- # attrs["type"] = "frequency"
538
- # attrs["units"] = sd["unit"]
539
- # attrs["frame"] = sd["system"]
540
- attrs["wave_unit"] = [sd["waveUnit"]]
553
+ attrs["type"] = "spectral_coord"
554
+ attrs["units"] = sd["unit"]
555
+ attrs["frame"] = sd["system"]
556
+ attrs["wave_units"] = sd["waveUnit"]
541
557
  # attrs["crval"] = sd["wcs"]["crval"]
542
558
  # attrs["cdelt"] = sd["wcs"]["cdelt"]
543
559
 
544
- attrs["reference_value"] = make_frequency_reference_dict(
560
+ attrs["reference_frequency"] = make_spectral_coord_reference_dict(
545
561
  value=sd["wcs"]["crval"],
546
562
  units=sd["unit"],
547
563
  observer=sd["system"],
@@ -672,7 +688,7 @@ def _get_time_values_attrs(cimage_coord_dict: dict) -> Tuple[List[float], dict]:
672
688
  attrs["type"] = "time"
673
689
  attrs["scale"] = cimage_coord_dict["obsdate"]["refer"]
674
690
  unit = cimage_coord_dict["obsdate"]["m0"]["unit"]
675
- attrs["units"] = unit if isinstance(unit, list) else [unit]
691
+ attrs["units"] = unit
676
692
  time_val = cimage_coord_dict["obsdate"]["m0"]["value"]
677
693
  attrs["format"] = _get_time_format(time_val, unit)
678
694
  return ([time_val], copy.deepcopy(attrs))
@@ -802,7 +818,7 @@ def _get_velocity_values_attrs(
802
818
  if not attrs:
803
819
  attrs["doppler_type"] = _doppler_types[0]
804
820
 
805
- attrs["units"] = ["m/s"]
821
+ attrs["units"] = "m/s"
806
822
  attrs["type"] = "doppler"
807
823
  return (
808
824
  _compute_velocity_values(
@@ -32,7 +32,10 @@ def _compute_direction_dict(xds: xr.Dataset) -> dict:
32
32
  direction["system"] = "J2000"
33
33
  direction["projection"] = xds_dir["projection"]
34
34
  direction["projection_parameters"] = xds_dir["projection_parameters"]
35
- direction["units"] = xds_dir["reference"]["attrs"]["units"]
35
+ direction["units"] = [
36
+ xds_dir["reference"]["attrs"]["units"],
37
+ xds_dir["reference"]["attrs"]["units"],
38
+ ]
36
39
  direction["crval"] = np.array(xds_dir["reference"]["data"])
37
40
  direction["cdelt"] = np.array((xds.l[1] - xds.l[0], xds.m[1] - xds.m[0]))
38
41
  direction["crpix"] = _compute_sky_reference_pixel(xds)
@@ -43,7 +46,7 @@ def _compute_direction_dict(xds: xr.Dataset) -> dict:
43
46
  m = "lonpole" if s == "longpole" else s
44
47
  # lonpole, latpole are numerical values in degrees in casa images
45
48
  direction[s] = float(
46
- Angle(str(xds_dir[m]["data"]) + xds_dir[m]["attrs"]["units"][0]).deg
49
+ Angle(str(xds_dir[m]["data"]) + xds_dir[m]["attrs"]["units"]).deg
47
50
  )
48
51
  return direction
49
52
 
@@ -87,20 +90,22 @@ def _compute_spectral_dict(xds: xr.Dataset) -> dict:
87
90
  spec["restfreq"] = xds.frequency.attrs["rest_frequency"]["data"]
88
91
  # spec["restfreqs"] = copy.deepcopy(xds.frequency.attrs["restfreqs"]["value"])
89
92
  spec["restfreqs"] = np.array([spec["restfreq"]])
90
- spec["system"] = xds.frequency.attrs["reference_value"]["attrs"]["observer"].upper()
91
- u = xds.frequency.attrs["reference_value"]["attrs"]["units"]
92
- spec["unit"] = u if isinstance(u, str) else u[0]
93
+ spec["system"] = xds.frequency.attrs["reference_frequency"]["attrs"][
94
+ "observer"
95
+ ].upper()
96
+ u = xds.frequency.attrs["reference_frequency"]["attrs"]["units"]
97
+ spec["unit"] = u
93
98
  spec["velType"] = _doppler_types.index(xds.velocity.attrs["doppler_type"])
94
99
  u = xds.velocity.attrs["units"]
95
100
  spec["version"] = 2
96
101
  # vel unit is a list[str] in the xds but needs to be a str in the casa image
97
- spec["velUnit"] = xds.velocity.attrs["units"][0]
102
+ spec["velUnit"] = xds.velocity.attrs["units"]
98
103
  # wave unit is a list[str] in the xds but needs to be a str in the casa image
99
- spec["waveUnit"] = xds.frequency.attrs["wave_unit"][0]
104
+ spec["waveUnit"] = xds.frequency.attrs["wave_units"]
100
105
  wcs = {}
101
106
  wcs["ctype"] = "FREQ"
102
107
  wcs["pc"] = 1.0
103
- wcs["crval"] = float(xds.frequency.attrs["reference_value"]["data"])
108
+ wcs["crval"] = float(xds.frequency.attrs["reference_frequency"]["data"])
104
109
  wcs["cdelt"] = float(xds.frequency.values[1] - xds.frequency.values[0])
105
110
  wcs["crpix"] = float((wcs["crval"] - xds.frequency.values[0]) / wcs["cdelt"])
106
111
  spec["wcs"] = wcs
@@ -114,26 +119,46 @@ def _coord_dict_from_xds(xds: xr.Dataset) -> dict:
114
119
  tel = xds[sky_ap].attrs["telescope"]
115
120
  if "name" in tel:
116
121
  coord["telescope"] = xds[sky_ap].attrs["telescope"]["name"]
117
- if "location" in tel:
118
- xds_telloc = tel["location"]
122
+
123
+ if "direction" in tel:
124
+ xds_telloc = tel["direction"]
119
125
  telloc = {}
120
126
  telloc["refer"] = xds_telloc["attrs"]["frame"]
121
127
  if telloc["refer"] == "GRS80":
122
128
  telloc["refer"] = "ITRF"
123
- for i in range(3):
129
+ for i in range(2):
124
130
  telloc[f"m{i}"] = {
125
- "unit": xds_telloc["attrs"]["units"][i],
131
+ "unit": xds_telloc["attrs"]["units"],
126
132
  "value": xds_telloc["data"][i],
127
133
  }
134
+ telloc[f"m{2}"] = {
135
+ "unit": tel["distance"]["attrs"]["units"],
136
+ "value": tel["distance"]["data"][0],
137
+ }
138
+
128
139
  telloc["type"] = "position"
129
140
  coord["telescopeposition"] = telloc
141
+
142
+ # if "location" in tel:
143
+ # xds_telloc = tel["location"]
144
+ # telloc = {}
145
+ # telloc["refer"] = xds_telloc["attrs"]["frame"]
146
+ # if telloc["refer"] == "GRS80":
147
+ # telloc["refer"] = "ITRF"
148
+ # for i in range(3):
149
+ # telloc[f"m{i}"] = {
150
+ # "unit": xds_telloc["attrs"]["units"],
151
+ # "value": xds_telloc["data"][i],
152
+ # }
153
+ # telloc["type"] = "position"
154
+ # coord["telescopeposition"] = telloc
130
155
  if "observer" in xds[sky_ap].attrs:
131
156
  coord["observer"] = xds[sky_ap].attrs["observer"]
132
157
  obsdate = {}
133
158
  obsdate["refer"] = xds.coords["time"].attrs["scale"]
134
159
  obsdate["type"] = "epoch"
135
160
  obsdate["m0"] = {}
136
- obsdate["m0"]["unit"] = xds.coords["time"].attrs["units"][0]
161
+ obsdate["m0"]["unit"] = xds.coords["time"].attrs["units"]
137
162
  obsdate["m0"]["value"] = float(xds.coords["time"].values[0])
138
163
  coord["obsdate"] = obsdate
139
164
  if _pointing_center in xds[sky_ap].attrs:
@@ -212,6 +237,7 @@ def _imageinfo_dict_from_xds(xds: xr.Dataset) -> dict:
212
237
  pp = {}
213
238
  pp["nChannels"] = xds.sizes["frequency"]
214
239
  pp["nStokes"] = xds.sizes["polarization"]
240
+
215
241
  bu = xds.BEAM.attrs["units"]
216
242
  chan = 0
217
243
  polarization = 0
@@ -229,6 +255,7 @@ def _imageinfo_dict_from_xds(xds: xr.Dataset) -> dict:
229
255
  chan = 0
230
256
  polarization += 1
231
257
  ii["perplanebeams"] = pp
258
+
232
259
  """
233
260
  elif "beam" in xds.attrs and xds.attrs["beam"]:
234
261
  # do nothing if xds.attrs['beam'] is None
@@ -236,7 +263,7 @@ def _imageinfo_dict_from_xds(xds: xr.Dataset) -> dict:
236
263
  for k in ["major", "minor", "pa"]:
237
264
  # print("*** ", k, ii["restoringbeam"][k])
238
265
  del ii["restoringbeam"][k]["dims"]
239
- ii["restoringbeam"][k]["unit"] = ii["restoringbeam"][k]["attrs"]["units"][0]
266
+ ii["restoringbeam"][k]["units"] = ii["restoringbeam"][k]["attrs"]["units"]
240
267
  del ii["restoringbeam"][k]["attrs"]
241
268
  ii["restoringbeam"][k]["value"] = ii["restoringbeam"][k]["data"]
242
269
  del ii["restoringbeam"][k]["data"]