xradio 0.0.50__tar.gz → 0.0.51__tar.gz

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 (84) hide show
  1. {xradio-0.0.50/src/xradio.egg-info → xradio-0.0.51}/PKG-INFO +10 -4
  2. xradio-0.0.51/README.md +27 -0
  3. {xradio-0.0.50 → xradio-0.0.51}/pyproject.toml +5 -2
  4. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/_utils/schema.py +2 -2
  5. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/_utils/_msv2/conversion.py +3 -3
  6. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/_utils/_msv2/create_antenna_xds.py +5 -5
  7. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/_utils/_msv2/create_field_and_source_xds.py +2 -1
  8. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/_utils/_msv2/msv4_sub_xdss.py +151 -13
  9. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/processing_set_xdt.py +146 -31
  10. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/schema.py +40 -25
  11. {xradio-0.0.50 → xradio-0.0.51/src/xradio.egg-info}/PKG-INFO +10 -4
  12. {xradio-0.0.50 → xradio-0.0.51}/src/xradio.egg-info/requires.txt +1 -1
  13. xradio-0.0.50/README.md +0 -21
  14. {xradio-0.0.50 → xradio-0.0.51}/LICENSE.txt +0 -0
  15. {xradio-0.0.50 → xradio-0.0.51}/MANIFEST.in +0 -0
  16. {xradio-0.0.50 → xradio-0.0.51}/setup.cfg +0 -0
  17. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/__init__.py +0 -0
  18. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/_utils/__init__.py +0 -0
  19. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/_utils/_casacore/tables.py +0 -0
  20. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/_utils/coord_math.py +0 -0
  21. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/_utils/dict_helpers.py +0 -0
  22. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/_utils/list_and_array.py +0 -0
  23. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/_utils/zarr/__init__.py +0 -0
  24. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/_utils/zarr/common.py +0 -0
  25. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/image/__init__.py +0 -0
  26. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/image/_util/__init__.py +0 -0
  27. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/image/_util/_casacore/__init__.py +0 -0
  28. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/image/_util/_casacore/common.py +0 -0
  29. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/image/_util/_casacore/xds_from_casacore.py +0 -0
  30. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/image/_util/_casacore/xds_to_casacore.py +0 -0
  31. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/image/_util/_fits/xds_from_fits.py +0 -0
  32. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/image/_util/_zarr/common.py +0 -0
  33. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/image/_util/_zarr/xds_from_zarr.py +0 -0
  34. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/image/_util/_zarr/xds_to_zarr.py +0 -0
  35. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/image/_util/_zarr/zarr_low_level.py +0 -0
  36. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/image/_util/casacore.py +0 -0
  37. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/image/_util/common.py +0 -0
  38. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/image/_util/fits.py +0 -0
  39. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/image/_util/image_factory.py +0 -0
  40. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/image/_util/zarr.py +0 -0
  41. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/image/image.py +0 -0
  42. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/__init__.py +0 -0
  43. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/_utils/__init__.py +0 -0
  44. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/_utils/_msv2/_tables/load.py +0 -0
  45. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/_utils/_msv2/_tables/load_main_table.py +0 -0
  46. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/_utils/_msv2/_tables/read.py +0 -0
  47. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/_utils/_msv2/_tables/read_main_table.py +0 -0
  48. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/_utils/_msv2/_tables/read_subtables.py +0 -0
  49. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/_utils/_msv2/_tables/table_query.py +0 -0
  50. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/_utils/_msv2/_tables/write.py +0 -0
  51. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/_utils/_msv2/_tables/write_exp_api.py +0 -0
  52. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/_utils/_msv2/chunks.py +0 -0
  53. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/_utils/_msv2/descr.py +0 -0
  54. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/_utils/_msv2/msv2_msv3.py +0 -0
  55. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/_utils/_msv2/msv2_to_msv4_meta.py +0 -0
  56. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/_utils/_msv2/msv4_info_dicts.py +0 -0
  57. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/_utils/_msv2/optimised_functions.py +0 -0
  58. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/_utils/_msv2/partition_queries.py +0 -0
  59. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/_utils/_msv2/partitions.py +0 -0
  60. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/_utils/_msv2/subtables.py +0 -0
  61. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/_utils/_utils/cds.py +0 -0
  62. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/_utils/_utils/partition_attrs.py +0 -0
  63. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/_utils/_utils/stokes_types.py +0 -0
  64. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/_utils/_utils/xds_helper.py +0 -0
  65. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/_utils/_zarr/encoding.py +0 -0
  66. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/_utils/_zarr/read.py +0 -0
  67. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/_utils/_zarr/write.py +0 -0
  68. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/_utils/msv2.py +0 -0
  69. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/_utils/zarr.py +0 -0
  70. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/convert_msv2_to_processing_set.py +0 -0
  71. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/load_processing_set.py +0 -0
  72. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/measurement_set_xdt.py +0 -0
  73. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/measurement_set/open_processing_set.py +0 -0
  74. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/schema/__init__.py +0 -0
  75. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/schema/bases.py +0 -0
  76. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/schema/check.py +0 -0
  77. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/schema/dataclass.py +0 -0
  78. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/schema/metamodel.py +0 -0
  79. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/schema/typing.py +0 -0
  80. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/sphinx/__init__.py +0 -0
  81. {xradio-0.0.50 → xradio-0.0.51}/src/xradio/sphinx/schema_table.py +0 -0
  82. {xradio-0.0.50 → xradio-0.0.51}/src/xradio.egg-info/SOURCES.txt +0 -0
  83. {xradio-0.0.50 → xradio-0.0.51}/src/xradio.egg-info/dependency_links.txt +0 -0
  84. {xradio-0.0.50 → xradio-0.0.51}/src/xradio.egg-info/top_level.txt +0 -0
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xradio
3
- Version: 0.0.50
3
+ Version: 0.0.51
4
4
  Summary: Xarray Radio Astronomy Data IO
5
- Author-email: Jan-Willem Steeb <jsteeb@nrao.edu>
5
+ Author-email: Jan-Willem Steeb <jsteeb@nrao.edu>, Federico Montesino Pouzols <pouzols@eso.edu>, Dave Mehringer <dmehring@nrao.edu>, Peter Wortmann <peter.wortmann@skao.int>
6
6
  License: BSD 3-Clause License
7
7
 
8
8
  All works in this repository are copyrighted 2024.
@@ -43,7 +43,7 @@ License-File: LICENSE.txt
43
43
  Requires-Dist: astropy
44
44
  Requires-Dist: dask
45
45
  Requires-Dist: distributed
46
- Requires-Dist: toolviper
46
+ Requires-Dist: toolviper>=0.0.11
47
47
  Requires-Dist: numba>=0.57.0
48
48
  Requires-Dist: numpy
49
49
  Requires-Dist: pytest
@@ -79,7 +79,13 @@ Dynamic: license-file
79
79
  # xradio
80
80
  Xarray Radio Astronomy Data IO is still in development.
81
81
 
82
- [![Python 3.9 3.10 3.11 3.12](https://img.shields.io/badge/python-3.9%20%7C%203.10%20%7C%203.11%203.12-blue)](https://www.python.org/downloads/release/python-380/)
82
+ [![Python 3.11 3.12 3.13](https://img.shields.io/badge/python-3.11%20%7C%203.12%20%7C%203.13-blue)](https://www.python.org/downloads/release/python-3130/)
83
+ ![Linux Tests](https://github.com/casangi/xradio/actions/workflows/python-testing-linux.yml/badge.svg?branch=main)
84
+ ![macOS Tests](https://github.com/casangi/xradio/actions/workflows/python-testing-macos.yml/badge.svg?branch=main)
85
+ ![ipynb Tests](https://github.com/casangi/xradio/actions/workflows/run-ipynb.yml/badge.svg?branch=main)
86
+ [![Coverage](https://codecov.io/gh/casangi/xradio/branch/main/graph/badge.svg)](https://codecov.io/gh/casangi/xradio/branch/main/xradio)
87
+ [![Documentation Status](https://readthedocs.org/projects/xradio/badge/?version=latest)](https://xradio.readthedocs.io)
88
+ [![Version Status](https://img.shields.io/pypi/v/xradio.svg)](https://pypi.python.org/pypi/xradio/)
83
89
 
84
90
  # Installing
85
91
  It is recommended to use the conda environment manager from [miniforge](https://github.com/conda-forge/miniforge) to create a clean, self-contained runtime where XRADIO and all its dependencies can be installed:
@@ -0,0 +1,27 @@
1
+ # xradio
2
+ Xarray Radio Astronomy Data IO is still in development.
3
+
4
+ [![Python 3.11 3.12 3.13](https://img.shields.io/badge/python-3.11%20%7C%203.12%20%7C%203.13-blue)](https://www.python.org/downloads/release/python-3130/)
5
+ ![Linux Tests](https://github.com/casangi/xradio/actions/workflows/python-testing-linux.yml/badge.svg?branch=main)
6
+ ![macOS Tests](https://github.com/casangi/xradio/actions/workflows/python-testing-macos.yml/badge.svg?branch=main)
7
+ ![ipynb Tests](https://github.com/casangi/xradio/actions/workflows/run-ipynb.yml/badge.svg?branch=main)
8
+ [![Coverage](https://codecov.io/gh/casangi/xradio/branch/main/graph/badge.svg)](https://codecov.io/gh/casangi/xradio/branch/main/xradio)
9
+ [![Documentation Status](https://readthedocs.org/projects/xradio/badge/?version=latest)](https://xradio.readthedocs.io)
10
+ [![Version Status](https://img.shields.io/pypi/v/xradio.svg)](https://pypi.python.org/pypi/xradio/)
11
+
12
+ # Installing
13
+ It is recommended to use the conda environment manager from [miniforge](https://github.com/conda-forge/miniforge) to create a clean, self-contained runtime where XRADIO and all its dependencies can be installed:
14
+ ```sh
15
+ conda create --name xradio python=3.12 --no-default-packages
16
+ conda activate xradio
17
+ ```
18
+ > 📝 On macOS it is required to pre-install `python-casacore` using `conda install -c conda-forge python-casacore`.
19
+
20
+ XRADIO can now be installed using:
21
+ ```sh
22
+ pip install xradio
23
+ ```
24
+ This will also install the minimal dependencies for XRADIO. To install the minimal dependencies and the interactive components (JupyterLab) use:
25
+ ```sh
26
+ pip install "xradio[interactive]"
27
+ ```
@@ -1,9 +1,12 @@
1
1
  [project]
2
2
  name = "xradio"
3
- version = "0.0.50"
3
+ version = "0.0.51"
4
4
  description = " Xarray Radio Astronomy Data IO"
5
5
  authors = [
6
6
  {name = "Jan-Willem Steeb", email="jsteeb@nrao.edu"},
7
+ {name = "Federico Montesino Pouzols", email="pouzols@eso.edu"},
8
+ {name = "Dave Mehringer", email="dmehring@nrao.edu"},
9
+ {name = "Peter Wortmann", email="peter.wortmann@skao.int"}
7
10
  ]
8
11
  license = {file = "LICENSE.txt"}
9
12
  readme = "README.md"
@@ -13,7 +16,7 @@ dependencies = [
13
16
  'astropy',
14
17
  'dask',
15
18
  'distributed',
16
- 'toolviper',
19
+ 'toolviper>=0.0.11',
17
20
  'numba>=0.57.0',
18
21
  'numpy',
19
22
  'pytest',
@@ -190,14 +190,14 @@ casacore_to_msv4_measure_type = {
190
190
  "LSRK": "lsrk",
191
191
  "LSRD": "lsrd",
192
192
  "BARY": "BARY",
193
- "GEO": "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": "GRS80"},
200
+ "Ref_map": {"ITRF": "ITRS"},
201
201
  },
202
202
  "uvw": {
203
203
  "type": "uvw",
@@ -1214,13 +1214,13 @@ def convert_and_write_partition(
1214
1214
  )
1215
1215
  # but before, keep the name-id arrays, we need them for the pointing and weather xds
1216
1216
  ant_xds_name_ids = ant_xds["antenna_name"].set_xindex("antenna_id")
1217
- ant_xds_station_name_ids = ant_xds["station"].set_xindex("antenna_id")
1217
+ ant_position_xds_with_ids = ant_xds["ANTENNA_POSITION"].set_xindex("antenna_id")
1218
1218
  # No longer needed after converting to name.
1219
1219
  ant_xds = ant_xds.drop_vars("antenna_id")
1220
1220
 
1221
1221
  # Create weather_xds
1222
1222
  start = time.time()
1223
- weather_xds = create_weather_xds(in_file, ant_xds_station_name_ids)
1223
+ weather_xds = create_weather_xds(in_file, ant_position_xds_with_ids)
1224
1224
  logger.debug("Time weather " + str(time.time() - start))
1225
1225
 
1226
1226
  # Create pointing_xds
@@ -1425,7 +1425,7 @@ def antenna_ids_to_names(
1425
1425
  "antenna_id",
1426
1426
  "antenna_name",
1427
1427
  "mount",
1428
- "station",
1428
+ "station_name",
1429
1429
  ]
1430
1430
  for unwanted_coord in unwanted_coords_from_ant_xds:
1431
1431
  xds = xds.drop_vars(unwanted_coord)
@@ -109,7 +109,7 @@ def extract_antenna_info(
109
109
 
110
110
  to_new_coords = {
111
111
  "NAME": ["antenna_name", ["antenna_name"]],
112
- "STATION": ["station", ["antenna_name"]],
112
+ "STATION": ["station_name", ["antenna_name"]],
113
113
  "MOUNT": ["mount", ["antenna_name"]],
114
114
  # "PHASED_ARRAY_ID": ["phased_array_id", ["antenna_name"]],
115
115
  "antenna_id": ["antenna_id", ["antenna_name"]],
@@ -158,9 +158,9 @@ def extract_antenna_info(
158
158
 
159
159
  # None of the native numpy functions work on the github test runner.
160
160
  antenna_name = ant_xds["antenna_name"].values
161
- station = ant_xds["station"].values
161
+ station_name = ant_xds["station_name"].values
162
162
  antenna_name = np.array(
163
- list(map(lambda x, y: x + "_" + y, antenna_name, station))
163
+ list(map(lambda x, y: x + "_" + y, antenna_name, station_name))
164
164
  )
165
165
 
166
166
  ant_xds["antenna_name"] = xr.DataArray(antenna_name, dims=["antenna_name"])
@@ -376,7 +376,7 @@ def create_gain_curve_xds(
376
376
 
377
377
  ant_borrowed_coords = {
378
378
  "antenna_name": ant_xds.coords["antenna_name"],
379
- "station": ant_xds.coords["station"],
379
+ "station_name": ant_xds.coords["station_name"],
380
380
  "mount": ant_xds.coords["mount"],
381
381
  "telescope_name": ant_xds.coords["telescope_name"],
382
382
  "receptor_label": ant_xds.coords["receptor_label"],
@@ -486,7 +486,7 @@ def create_phase_calibration_xds(
486
486
 
487
487
  ant_borrowed_coords = {
488
488
  "antenna_name": ant_xds.coords["antenna_name"],
489
- "station": ant_xds.coords["station"],
489
+ "station_name": ant_xds.coords["station_name"],
490
490
  "mount": ant_xds.coords["mount"],
491
491
  "telescope_name": ant_xds.coords["telescope_name"],
492
492
  "receptor_label": ant_xds.coords["receptor_label"],
@@ -226,9 +226,10 @@ def extract_ephemeris_info(
226
226
  "type": "location",
227
227
  "units": ["deg", "deg", "m"],
228
228
  "data": observer_position,
229
- "frame": "WGS84",
229
+ "frame": "ITRS",
230
230
  "origin_object_name": "Earth",
231
231
  "coordinate_system": ephemeris_meta["obsloc"].lower(),
232
+ "ellipsoid": "WGS84",
232
233
  }
233
234
  ) # I think the units are ['deg','deg','m'] and 'WGS84'.
234
235
 
@@ -172,7 +172,130 @@ def make_taql_where_weather(
172
172
  return taql_where
173
173
 
174
174
 
175
- def create_weather_xds(in_file: str, ant_xds_station_name_ids: xr.DataArray):
175
+ def prepare_generic_weather_xds_and_station_name(
176
+ generic_weather_xds: xr.Dataset,
177
+ in_file: str,
178
+ ant_position_with_ids: xr.DataArray,
179
+ has_asdm_station_position: bool,
180
+ ) -> tuple[xr.Dataset, np.ndarray]:
181
+ """
182
+ A generic_weather_xds loaded with load_generic_table() might still need to be reloaded
183
+ with an additional WHERE condition to constrain the indices of antennas. But this depends on whether
184
+ ASDM/importasdm extension columns are present or not.
185
+
186
+ This also prepares the station_name values:
187
+ - if has_asdm_station_ids:
188
+ - tries to find from ASDM_STATION the station names,
189
+ - otherwise, takes ids (antenna_ids in generic_weather were actually the ASDM_STATION_IDs
190
+ - else: get the values from antenna_xds (the stations present)
191
+
192
+
193
+ Parameters
194
+ ----------
195
+ generic_weather_xds : xr.Dataset
196
+ generic dataset read from an MSv2 WEATHER subtable
197
+ in_file : str
198
+ Input MS name.
199
+ ant_position_with_ids : xr.DataArray
200
+ antenna_position data var from the antenna_xds (expected to still include the initial ANTENNA_ID
201
+ coordinate as well as other coordinates from the antenna_xds)
202
+ has_asdm_station_position : bool
203
+ wHether this generic weatehr_xds should be treated as including the nonstandard extensions
204
+ NS_WX_STATION_ID and NS_WX_STATION_POSITION as created by CASA/importasdm (ALMA and VLA).
205
+
206
+ Returns
207
+ -------
208
+ (generic_weather_xds, station_name): tuple[[xarray.Dataset, numpy.ndarray]
209
+ Weather Xarray Dataset prepared for generic conversion to MSv4, values for the station_name coordinate
210
+ """
211
+
212
+ if has_asdm_station_position:
213
+ asdm_station_path = os.path.join(in_file, "ASDM_STATION")
214
+ if table_exists(asdm_station_path):
215
+ asdm_station_xds = load_generic_table(in_file, "ASDM_STATION")
216
+ station_name = asdm_station_xds.name.values[
217
+ generic_weather_xds["ANTENNA_ID"].values
218
+ ]
219
+ else:
220
+ # if no info from ASDM_STATION, use the indices from antenna_id which was actually the NS_WX_STATION_ID
221
+ len_antenna_id = generic_weather_xds.sizes["ANTENNA_ID"]
222
+ station_name = list(
223
+ map(
224
+ lambda x, y: x + "_" + y,
225
+ ["Station"] * len_antenna_id,
226
+ generic_weather_xds["ANTENNA_ID"].values.astype(str),
227
+ )
228
+ )
229
+
230
+ else:
231
+ taql_where = make_taql_where_weather(in_file, ant_position_with_ids)
232
+ generic_weather_xds = load_generic_table(
233
+ in_file,
234
+ "WEATHER",
235
+ rename_ids=subt_rename_ids["WEATHER"],
236
+ taql_where=taql_where,
237
+ )
238
+
239
+ if not generic_weather_xds.data_vars:
240
+ # for example when the weather subtable only has info for antennas/stations
241
+ # not present in the MSv4 (no overlap between antennas loaded in ant_xds and weather)
242
+ return None, None
243
+
244
+ stations_present = ant_position_with_ids.sel(
245
+ antenna_id=generic_weather_xds["ANTENNA_ID"]
246
+ ).station_name
247
+ station_name = stations_present.values
248
+
249
+ return generic_weather_xds, station_name
250
+
251
+
252
+ def finalize_station_position(
253
+ weather_xds: xr.Dataset, ant_position_with_ids, has_asdm_station_position: bool
254
+ ) -> xr.Dataset:
255
+ """
256
+ For a STATION_POSITION data var being added to a weather_xds, make sure coordinates and dimensions
257
+ are conforming to the schema.
258
+
259
+ Parameters
260
+ ----------
261
+ weather_xds : xr.Dataset
262
+ weather_xds where we still need to ensure the right coordinates and attributes
263
+ ant_position_with_ids : xr.DataArray
264
+ antenna_position data var from the antenna_xds (expected to still include the initial ANTENNA_ID
265
+ coordinate as well as other coordinates from the antenna_xds)
266
+ has_asdm_station_position : bool
267
+ Whether this generic weatehr_xds should be treated as including the nonstandard extensions
268
+ NS_WX_STATION_ID and NS_WX_STATION_POSITION as created by CASA/importasdm (ALMA and VLA).
269
+
270
+ Returns
271
+ -------
272
+ weather_xds: xarray.Dataset
273
+ Weather Xarray Dataset with all coordinates and attributes in STATION_POSITION
274
+ """
275
+ if has_asdm_station_position:
276
+ # STATION_POSITION has been created but needs prooper dimensions and attrs
277
+ # Drop the time dim
278
+ weather_xds["STATION_POSITION"] = weather_xds["STATION_POSITION"].sel(
279
+ time_weather=0, drop=True, method="nearest"
280
+ )
281
+ # borrow location frame attributes from antenna position
282
+ weather_xds["STATION_POSITION"].attrs = ant_position_with_ids.attrs
283
+ else:
284
+ # borrow from ant_posision_with_ids but without carrying over other coords
285
+ weather_xds = weather_xds.assign(
286
+ {
287
+ "STATION_POSITION": (
288
+ ["station_name", "cartesian_pos_label"],
289
+ ant_position_with_ids.values,
290
+ ant_position_with_ids.attrs,
291
+ )
292
+ }
293
+ )
294
+
295
+ return weather_xds
296
+
297
+
298
+ def create_weather_xds(in_file: str, ant_position_with_ids: xr.DataArray):
176
299
  """
177
300
  Creates a Weather Xarray Dataset from a MS v2 WEATHER table.
178
301
 
@@ -180,8 +303,9 @@ def create_weather_xds(in_file: str, ant_xds_station_name_ids: xr.DataArray):
180
303
  ----------
181
304
  in_file : str
182
305
  Input MS name.
183
- ant_xds_station_name_ids : xr.DataArray
184
- station name data array from antenna_xds, with name/id information
306
+ ant_position_with_ids : xr.DataArray
307
+ antenna_position data var from the antenna_xds (expected to still including the initial ANTENNA_ID coordinate
308
+ as wellas other coordinates from the antenna_xds)
185
309
 
186
310
  Returns
187
311
  -------
@@ -190,32 +314,32 @@ def create_weather_xds(in_file: str, ant_xds_station_name_ids: xr.DataArray):
190
314
  """
191
315
 
192
316
  try:
193
- taql_where = make_taql_where_weather(in_file, ant_xds_station_name_ids)
194
317
  generic_weather_xds = load_generic_table(
195
318
  in_file,
196
319
  "WEATHER",
197
320
  rename_ids=subt_rename_ids["WEATHER"],
198
- taql_where=taql_where,
199
321
  )
200
322
  except ValueError as _exc:
201
323
  return None
202
324
 
203
- if not generic_weather_xds.data_vars:
204
- # for example when the weather subtable only has info for antennas/stations
205
- # not present in the MSv4 (no overlap between antennas loaded in ant_xds and weather)
325
+ has_asdm_station_position = (
326
+ "NS_WX_STATION_POSITION" in generic_weather_xds.data_vars
327
+ )
328
+ generic_weather_xds, station_name = prepare_generic_weather_xds_and_station_name(
329
+ generic_weather_xds, in_file, ant_position_with_ids, has_asdm_station_position
330
+ )
331
+ if not generic_weather_xds:
206
332
  return None
207
333
 
208
334
  weather_xds = xr.Dataset(attrs={"type": "weather"})
209
- stations_present = ant_xds_station_name_ids.sel(
210
- antenna_id=generic_weather_xds["ANTENNA_ID"]
211
- )
212
335
  coords = {
213
- "station_name": stations_present.data,
214
- "antenna_name": stations_present.coords["antenna_name"].data,
336
+ "station_name": station_name,
337
+ "cartesian_pos_label": ["x", "y", "z"],
215
338
  }
216
339
  weather_xds = weather_xds.assign_coords(coords)
217
340
 
218
341
  dims_station_time = ["station_name", "time_weather"]
342
+ dims_station_time_position = dims_station_time + ["cartesian_pos_label"]
219
343
  to_new_data_variables = {
220
344
  "H20": ["H2O", dims_station_time],
221
345
  "IONOS_ELECTRON": ["IONOS_ELECTRON", dims_station_time],
@@ -226,6 +350,15 @@ def create_weather_xds(in_file: str, ant_xds_station_name_ids: xr.DataArray):
226
350
  "WIND_DIRECTION": ["WIND_DIRECTION", dims_station_time],
227
351
  "WIND_SPEED": ["WIND_SPEED", dims_station_time],
228
352
  }
353
+ if has_asdm_station_position:
354
+ to_new_data_variables.update(
355
+ {
356
+ "NS_WX_STATION_POSITION": [
357
+ "STATION_POSITION",
358
+ dims_station_time_position,
359
+ ],
360
+ }
361
+ )
229
362
 
230
363
  to_new_coords = {
231
364
  "TIME": ["time_weather", ["time_weather"]],
@@ -234,6 +367,9 @@ def create_weather_xds(in_file: str, ant_xds_station_name_ids: xr.DataArray):
234
367
  weather_xds = convert_generic_xds_to_xradio_schema(
235
368
  generic_weather_xds, weather_xds, to_new_data_variables, to_new_coords
236
369
  )
370
+ weather_xds = finalize_station_position(
371
+ weather_xds, ant_position_with_ids, has_asdm_station_position
372
+ )
237
373
 
238
374
  # TODO: option to interpolate to main time
239
375
 
@@ -256,6 +392,7 @@ def correct_generic_pointing_xds(
256
392
  and tries to correct several deviations from the MSv2 specs seen in
257
393
  common test data.
258
394
  The problems fixed here include wrong dimensions:
395
+
259
396
  - for example transposed dimensions with respect to the MSv2 specs (output
260
397
  from CASA simulator),
261
398
  - missing/additional unexpected dimensions when some of the columns are
@@ -423,6 +560,7 @@ def prepare_generic_sys_cal_xds(generic_sys_cal_xds: xr.Dataset) -> xr.Dataset:
423
560
  sys_cal_xds dataset, as their structure differs in dimensions and order
424
561
  of dimensions.
425
562
  This function performs various prepareation steps, such as:
563
+
426
564
  - filter out dimensions not neeed for an individual MSv4 (SPW, FEED),
427
565
  - drop variables loaded from columns with all items set to empty array,
428
566
  - transpose the dimensions frequency,receptor
@@ -569,6 +569,17 @@ class ProcessingSetXdt:
569
569
  ValueError
570
570
  If the combined datasets are empty or improperly formatted.
571
571
  """
572
+
573
+ def setup_annotations_all(axis, scatter, field_names):
574
+ """
575
+ Creates annotations for when label_all_fields=True
576
+ """
577
+ coord_x, coord_y = np.array(scatter.get_offsets()).transpose()
578
+ offset_x = np.abs(np.max(coord_x) - np.min(coord_x)) * 0.01
579
+ offset_y = np.abs(np.max(coord_y) - np.min(coord_y)) * 0.01
580
+ for idx, (x, y) in enumerate(zip(coord_x + offset_x, coord_y + offset_y)):
581
+ axis.annotate(field_names[idx], (x, y), alpha=1)
582
+
572
583
  if self._xdt.attrs.get("type") not in PS_DATASET_TYPES:
573
584
  raise InvalidAccessorLocation(
574
585
  f"{self._xdt.path} is not a processing set node."
@@ -585,9 +596,9 @@ class ProcessingSetXdt:
585
596
  if (len(combined_field_and_source_xds.data_vars) > 0) and (
586
597
  "FIELD_PHASE_CENTER" in combined_field_and_source_xds
587
598
  ):
588
- plt.figure()
599
+ fig = plt.figure()
589
600
  plt.title("Field Phase Center Locations")
590
- plt.scatter(
601
+ scatter = plt.scatter(
591
602
  combined_field_and_source_xds["FIELD_PHASE_CENTER"].sel(
592
603
  sky_dir_label="ra"
593
604
  ),
@@ -595,31 +606,40 @@ class ProcessingSetXdt:
595
606
  sky_dir_label="dec"
596
607
  ),
597
608
  )
598
-
599
609
  center_field_name = combined_field_and_source_xds.attrs["center_field_name"]
600
610
  center_field = combined_field_and_source_xds.sel(
601
611
  field_name=center_field_name
602
612
  )
613
+
614
+ if label_all_fields:
615
+ field_name = combined_field_and_source_xds.field_name.values
616
+ setup_annotations_all(fig.axes[0], scatter, field_name)
617
+ fig.axes[0].margins(0.2, 0.2)
618
+ center_label = None
619
+ else:
620
+ center_label = center_field_name
621
+
603
622
  plt.scatter(
604
623
  center_field["FIELD_PHASE_CENTER"].sel(sky_dir_label="ra"),
605
624
  center_field["FIELD_PHASE_CENTER"].sel(sky_dir_label="dec"),
606
625
  color="red",
607
- label=center_field_name,
626
+ label=center_label,
608
627
  )
609
628
  plt.xlabel("RA (rad)")
610
629
  plt.ylabel("DEC (rad)")
611
- plt.legend()
630
+ if not label_all_fields:
631
+ plt.legend()
612
632
  plt.show()
613
633
 
614
634
  if (len(combined_ephemeris_field_and_source_xds.data_vars) > 0) and (
615
635
  "FIELD_PHASE_CENTER" in combined_ephemeris_field_and_source_xds
616
636
  ):
617
637
 
618
- plt.figure()
638
+ fig = plt.figure()
619
639
  plt.title(
620
640
  "Offset of Field Phase Center from Source Location (Ephemeris Data)"
621
641
  )
622
- plt.scatter(
642
+ scatter = plt.scatter(
623
643
  combined_ephemeris_field_and_source_xds["FIELD_OFFSET"].sel(
624
644
  sky_dir_label="ra"
625
645
  ),
@@ -639,15 +659,26 @@ class ProcessingSetXdt:
639
659
  center_field = combined_ephemeris_field_and_source_xds.sel(
640
660
  field_name=center_field_name
641
661
  )
662
+
663
+ if label_all_fields:
664
+ field_name = combined_ephemeris_field_and_source_xds.field_name.values
665
+ setup_annotations_all(fig.axes[0], scatter, field_name)
666
+ fig.axes[0].margins(0.2, 0.2)
667
+ center_label = None
668
+ else:
669
+ center_label = center_field_name
670
+
642
671
  plt.scatter(
643
672
  center_field["FIELD_OFFSET"].sel(sky_dir_label="ra"),
644
673
  center_field["FIELD_OFFSET"].sel(sky_dir_label="dec"),
645
674
  color="red",
646
- label=center_field_name,
675
+ label=center_label,
647
676
  )
677
+
648
678
  plt.xlabel("RA Offset (rad)")
649
679
  plt.ylabel("DEC Offset (rad)")
650
- plt.legend()
680
+ if not label_all_fields:
681
+ plt.legend()
651
682
  plt.show()
652
683
 
653
684
  def get_combined_antenna_xds(self) -> xr.Dataset:
@@ -693,18 +724,23 @@ class ProcessingSetXdt:
693
724
 
694
725
  return combined_antenna_xds
695
726
 
696
- def plot_antenna_positions(self):
727
+ def plot_antenna_positions(self, label_all_antennas: bool = False):
697
728
  """
698
729
  Plot the antenna positions of all antennas in the Processing Set.
699
730
 
700
- This method generates three scatter plots displaying the antenna positions in different planes:
731
+ This method generates and displays a figure with three scatter plots, displaying the antenna
732
+ positions in different planes:
733
+
701
734
  - X vs Y
702
735
  - X vs Z
703
736
  - Y vs Z
704
737
 
738
+ The antenna names are shown on hovering their positions, unless label_all_antennas is enabled.
739
+
705
740
  Parameters
706
741
  ----------
707
- None
742
+ label_all_antennas : bool, optional
743
+ If 'True', annotations are shown with the names of every antenna next to their positions.
708
744
 
709
745
  Returns
710
746
  -------
@@ -715,6 +751,75 @@ class ProcessingSetXdt:
715
751
  ValueError
716
752
  If the combined antenna dataset is empty or missing required coordinates.
717
753
  """
754
+
755
+ def antenna_hover(event):
756
+ if event.inaxes in antenna_axes:
757
+ for axis in antenna_axes:
758
+ contained, indices = scatter_map[axis].contains(event)
759
+ annotation = annotations_map[axis]
760
+ if contained:
761
+ scatter = scatter_map[axis]
762
+ update_antenna_annotation(indices, scatter, annotation)
763
+ annotation.set_visible(True)
764
+ fig.canvas.draw_idle()
765
+ else:
766
+ visible = annotation.get_visible()
767
+ if visible:
768
+ annotation.set_visible(False)
769
+ fig.canvas.draw_idle()
770
+
771
+ def update_antenna_annotation(indices, scatter, annotation):
772
+ position = scatter.get_offsets()[indices["ind"][0]]
773
+ annotation.xy = position
774
+ text = "{}".format(" ".join([antenna_names[num] for num in indices["ind"]]))
775
+ annotation.set_text(text)
776
+ annotation.get_bbox_patch().set_facecolor("#e8d192")
777
+ annotation.get_bbox_patch().set_alpha(1)
778
+
779
+ def setup_annotations_for_hover(antenna_axes, scatter_plots):
780
+ """
781
+ Creates annotations on all the axes requested.
782
+
783
+ Returns
784
+ -------
785
+ dict
786
+ dict from antenna axes -> annotation objects
787
+ """
788
+ antenna_annotations = []
789
+ for axis in antenna_axes:
790
+ annotation = axis.annotate(
791
+ "",
792
+ xy=(0, 0),
793
+ xytext=(10, 15),
794
+ textcoords="offset points",
795
+ arrowprops=dict(arrowstyle="-|>"),
796
+ bbox=dict(boxstyle="round", fc="w"),
797
+ )
798
+ antenna_annotations.append(annotation)
799
+ annotation.set_visible(False)
800
+ annotations_map = dict(zip(antenna_axes, antenna_annotations))
801
+
802
+ return annotations_map
803
+
804
+ def setup_annotations_for_all(antenna_axes, scatter_map):
805
+ """
806
+ Creates annotations for when label_all_antennas=True
807
+ """
808
+ antenna_annotations = []
809
+ for axis in antenna_axes:
810
+ scatter = scatter_map[axis]
811
+ coord_x, coord_y = np.array(scatter.get_offsets()).transpose()
812
+ offset_x = np.abs(np.max(coord_x) - np.min(coord_x)) * 0.01
813
+ offset_y = np.abs(np.max(coord_y) - np.min(coord_y)) * 0.01
814
+ for idx, (x, y) in enumerate(
815
+ zip(coord_x + offset_x, coord_y + offset_y)
816
+ ):
817
+ annotation = axis.annotate(
818
+ antenna_names[idx],
819
+ (x, y),
820
+ alpha=1,
821
+ )
822
+
718
823
  if self._xdt.attrs.get("type") not in PS_DATASET_TYPES:
719
824
  raise InvalidAccessorLocation(
720
825
  f"{self._xdt.path} is not a processing set node."
@@ -723,34 +828,44 @@ class ProcessingSetXdt:
723
828
  combined_antenna_xds = self.get_combined_antenna_xds()
724
829
  from matplotlib import pyplot as plt
725
830
 
726
- plt.figure()
727
- plt.title("Antenna Positions")
728
- plt.scatter(
831
+ fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(12, 8))
832
+ fig.suptitle("Antenna Positions")
833
+ fig.subplots_adjust(
834
+ wspace=0.25, hspace=0.25, left=0.1, right=0.95, top=0.9, bottom=0.1
835
+ )
836
+
837
+ scatter1 = ax1.scatter(
729
838
  combined_antenna_xds["ANTENNA_POSITION"].sel(cartesian_pos_label="x"),
730
839
  combined_antenna_xds["ANTENNA_POSITION"].sel(cartesian_pos_label="y"),
731
840
  )
732
- plt.xlabel("x (m)")
733
- plt.ylabel("y (m)")
734
- plt.show()
841
+ ax1.set_xlabel("x (m)")
842
+ ax1.set_ylabel("y (m)")
843
+ antenna_names = combined_antenna_xds.antenna_name.values
735
844
 
736
- plt.figure()
737
- plt.title("Antenna Positions")
738
- plt.scatter(
739
- combined_antenna_xds["ANTENNA_POSITION"].sel(cartesian_pos_label="x"),
845
+ scatter2 = ax2.scatter(
846
+ combined_antenna_xds["ANTENNA_POSITION"].sel(cartesian_pos_label="y"),
740
847
  combined_antenna_xds["ANTENNA_POSITION"].sel(cartesian_pos_label="z"),
741
848
  )
742
- plt.xlabel("x (m)")
743
- plt.ylabel("z (m)")
744
- plt.show()
849
+ ax2.set_xlabel("y (m)")
850
+ ax2.set_ylabel("z (m)")
745
851
 
746
- plt.figure()
747
- plt.title("Antenna Positions")
748
- plt.scatter(
749
- combined_antenna_xds["ANTENNA_POSITION"].sel(cartesian_pos_label="y"),
852
+ scatter3 = ax3.scatter(
853
+ combined_antenna_xds["ANTENNA_POSITION"].sel(cartesian_pos_label="x"),
750
854
  combined_antenna_xds["ANTENNA_POSITION"].sel(cartesian_pos_label="z"),
751
855
  )
752
- plt.xlabel("y (m)")
753
- plt.ylabel("z (m)")
856
+ ax3.set_xlabel("x (m)")
857
+ ax3.set_ylabel("z (m)")
858
+
859
+ ax4.axis("off")
860
+
861
+ antenna_axes = [ax1, ax2, ax3]
862
+ scatter_map = dict(zip(antenna_axes, [scatter1, scatter2, scatter3]))
863
+ if label_all_antennas:
864
+ annotations_map = setup_annotations_for_all(antenna_axes, scatter_map)
865
+ else:
866
+ annotations_map = setup_annotations_for_hover(antenna_axes, scatter_map)
867
+ fig.canvas.mpl_connect("motion_notify_event", antenna_hover)
868
+
754
869
  plt.show()
755
870
 
756
871
 
@@ -27,7 +27,7 @@ TimeWeather = Literal["time_weather"]
27
27
  AntennaName = Literal["antenna_name"]
28
28
  """ Antenna name dimension """
29
29
  StationName = Literal["station_name"]
30
- """ Station identifier dimension """
30
+ """ Station name dimension """
31
31
  ReceptorLabel = Literal["receptor_label"]
32
32
  """ Receptor label dimension """
33
33
  ToneLabel = Literal["tone_label"]
@@ -295,7 +295,7 @@ class SkyCoordArray:
295
295
 
296
296
  type: Attr[SkyCoord] = "sky_coord"
297
297
  units: Attr[UnitsOfSkyCoordInRadians] = ("rad", "rad")
298
- frame: Attr[AllowedSkyCoordFrames] = ""
298
+ frame: Attr[AllowedSkyCoordFrames] = "icrs"
299
299
  """
300
300
  Possible values are astropy SkyCoord frames.
301
301
  Several casacore frames found in MSv2 are translated to astropy frames as follows: AZELGEO=>altaz, J2000=>fk5, ICRS=>icrs.
@@ -324,7 +324,7 @@ class PointingBeamArray:
324
324
 
325
325
  type: Attr[SkyCoord] = "sky_coord"
326
326
  units: Attr[UnitsOfSkyCoordInRadians] = ("rad", "rad")
327
- frame: Attr[AllowedSkyCoordFrames] = "fk5"
327
+ frame: Attr[AllowedSkyCoordFrames] = "icrs"
328
328
  """
329
329
  From fixvis docs: clean and the im tool ignore the reference frame claimed by the UVW column (it is often mislabelled
330
330
  as ITRF when it is really FK5 (J2000)) and instead assume the (u, v, w)s are in the same frame as the phase tracking
@@ -341,7 +341,7 @@ class LocalSkyCoordArray:
341
341
 
342
342
  type: Attr[SkyCoord] = "sky_coord"
343
343
  units: Attr[UnitsOfSkyCoordInRadians] = ("rad", "rad")
344
- frame: Attr[AllowedSkyCoordFrames] = "fk5"
344
+ frame: Attr[AllowedSkyCoordFrames] = "icrs"
345
345
  """
346
346
  From fixvis docs: clean and the im tool ignore the reference frame claimed by the UVW column (it is often mislabelled
347
347
  as ITRF when it is really FK5 (J2000)) and instead assume the (u, v, w)s are in the same frame as the phase tracking
@@ -518,7 +518,7 @@ AllowedSpectralCoordFrames = Literal[
518
518
  # "LSRK" -> "lsrk",
519
519
  # "LSRD" -> "lsrd",
520
520
  "BARY",
521
- "GEO",
521
+ # "GEO", -> "gcrs"
522
522
  "TOPO",
523
523
  # astropy frames
524
524
  "gcrs",
@@ -540,17 +540,20 @@ class SpectralCoordArray:
540
540
 
541
541
  units: Attr[UnitsHertz] = ("Hz",)
542
542
 
543
- observer: Attr[AllowedSpectralCoordFrames] = "gcrs"
543
+ observer: Attr[AllowedSpectralCoordFrames] = "icrs"
544
544
  """
545
545
  Capitalized reference observers are from casacore. TOPO implies creating astropy earth_location.
546
546
  Astropy velocity reference frames are lowercase. Note that Astropy does not use the name 'TOPO' (telescope centric)
547
547
  rather it assumes if no velocity frame is given that this is the default.
548
+
549
+ When converting from MSv2 and casacore frequency frames, the following translations from casacore to astropy
550
+ frame names are applied: GEO=>gcrs, LSRK=>lsrk, LSRD=>lsrd
548
551
  """
549
552
 
550
553
  type: Attr[SpectralCoord] = "spectral_coord"
551
554
 
552
555
 
553
- AllowedLocationFrames = Literal["ITRF", "GRS80", "WGS84", "WGS72", "Undefined"]
556
+ AllowedLocationFrames = Literal["ITRS", "Undefined"]
554
557
 
555
558
 
556
559
  AllowedLocationCoordinateSystems = Literal[
@@ -562,11 +565,16 @@ AllowedLocationCoordinateSystems = Literal[
562
565
  ]
563
566
 
564
567
 
568
+ AllowedEllipsoid = Literal["GRS80", "WGS84", "WGS72"]
569
+
570
+
565
571
  @xarray_dataarray_schema
566
572
  class LocationArray:
567
573
  """
568
- Measure type used for example in antenna_xds/ANTENNA_POSITION, field_and_source_xds/OBSERVER_POSITION
569
- Data dimensions can be EllipsoidPosLabel or CartesianPosLabel
574
+ Measure type used for example in antenna_xds/ANTENNA_POSITION, weather_xds/STATION_POSITION,
575
+ field_and_source_xds(ephemeris)/OBSERVER_POSITION.
576
+
577
+ Data dimensions can be CartesianPosLabel or EllipsoidPosLabel
570
578
  """
571
579
 
572
580
  data: Data[Union[EllipsoidPosLabel, CartesianPosLabel], float]
@@ -575,13 +583,13 @@ class LocationArray:
575
583
  """
576
584
  If the units are a list of strings then it must be the same length as
577
585
  the last dimension of the data array. This allows for having different
578
- units in the same data array,for example geodetic coordinates could use
586
+ units in the same data array, for example geodetic coordinates could use
579
587
  ``['rad','rad','m']``.
580
588
  """
581
589
 
582
590
  frame: Attr[AllowedLocationFrames]
583
591
  """
584
- Can be ITRF, GRS80, WGS84, WGS72, Undefined
592
+ Reference frame. Can be ITRS (assumed for all Earth locations) or Undefined (used in non-Earth locations).
585
593
  """
586
594
 
587
595
  coordinate_system: Attr[AllowedLocationCoordinateSystems]
@@ -589,24 +597,29 @@ class LocationArray:
589
597
 
590
598
  origin_object_name: Attr[str]
591
599
  """
592
- earth/sun/moon/etc
600
+ earth/sun/moon/etc.
601
+ """
602
+
603
+ ellipsoid: Optional[Attr[AllowedEllipsoid]]
604
+ """
605
+ Ellipsoid used in geodetic Earth locations (with EllipsoidPosLabel coordinate)
593
606
  """
594
607
 
595
608
  type: Attr[Location] = "location"
596
- """ """
609
+ """ Measure type. Should be ``"location"``."""
597
610
 
598
611
 
599
612
  @xarray_dataarray_schema
600
613
  class EllipsoidPosLocationArray:
601
614
  """
602
- Measure type used for example in field_and_source_xds/SUB_OBSERVER_POSITION, SUB_SOLAR_POSITION
615
+ Measure type used for example in field_and_source_xds(ephemeris) / SUB_OBSERVER_DIRECTION, SUB_SOLAR_POSITION
603
616
  """
604
617
 
605
618
  data: Data[EllipsoidPosLabel, float]
606
619
 
607
620
  frame: Attr[AllowedLocationFrames]
608
621
  """
609
- Can be ITRF, GRS80, WGS84, WGS72
622
+ Reference frame. Can be ITRS (assumed for all Earth locations) or Undefined (used in non-Earth locations).
610
623
  """
611
624
 
612
625
  coordinate_system: Attr[AllowedLocationCoordinateSystems]
@@ -618,7 +631,7 @@ class EllipsoidPosLocationArray:
618
631
  """
619
632
 
620
633
  type: Attr[Location] = "location"
621
- """ """
634
+ """ Measure type. Should be ``"location"``."""
622
635
 
623
636
  units: Attr[UnitsOfPositionInRadians] = ("rad", "rad", "m")
624
637
  """
@@ -1445,7 +1458,7 @@ class AntennaXds:
1445
1458
  # Coordinates
1446
1459
  antenna_name: Coordof[AntennaNameArray]
1447
1460
  """ Antenna name """
1448
- station: Coord[AntennaName, str]
1461
+ station_name: Coord[AntennaName, str]
1449
1462
  """ Name of the station pad (relevant to arrays with moving antennas). """
1450
1463
  mount: Coord[AntennaName, str]
1451
1464
  """ Mount type of the antenna. Reserved keywords include: ”EQUATORIAL” - equatorial mount;
@@ -1529,7 +1542,7 @@ class GainCurveXds:
1529
1542
  # Coordinates
1530
1543
  antenna_name: Coordof[AntennaNameArray]
1531
1544
  """ Antenna name """
1532
- station: Coord[AntennaName, str]
1545
+ station_name: Coord[AntennaName, str]
1533
1546
  """ Name of the station pad (relevant to arrays with moving antennas). """
1534
1547
  mount: Coord[AntennaName, str]
1535
1548
  """ Mount type of the antenna. Reserved keywords include: ”EQUATORIAL” - equatorial mount;
@@ -1588,7 +1601,7 @@ class PhaseCalibrationXds:
1588
1601
  # Coordinates
1589
1602
  antenna_name: Coordof[AntennaNameArray]
1590
1603
  """ Antenna name """
1591
- station: Coord[AntennaName, str]
1604
+ station_name: Coord[AntennaName, str]
1592
1605
  """ Name of the station pad (relevant to arrays with moving antennas). """
1593
1606
  mount: Coord[AntennaName, str]
1594
1607
  """ Mount type of the antenna. Reserved keywords include: ”EQUATORIAL” - equatorial mount;
@@ -1672,13 +1685,11 @@ class WeatherXds:
1672
1685
 
1673
1686
  # Coordinates
1674
1687
  station_name: Coord[StationName, str]
1675
- """ Station identifier """
1688
+ """ Station name """
1676
1689
  time: Optional[Coordof[TimeInterpolatedCoordArray]]
1677
1690
  """ Mid-point of the time interval. Labeled 'time' when interpolated to main time axis """
1678
1691
  time_weather: Optional[Coordof[TimeWeatherCoordArray]]
1679
1692
  """ Mid-point of the time interval. Labeled 'time_weather' when not interpolated to main time axis """
1680
- antenna_name: Optional[Coordof[AntennaNameArray]]
1681
- """ Antenna identifier """
1682
1693
  ellipsoid_pos_label: Optional[Coord[EllipsoidPosLabel, str]] = (
1683
1694
  "lon",
1684
1695
  "lat",
@@ -1688,6 +1699,10 @@ class WeatherXds:
1688
1699
  cartesian_pos_label: Optional[Coord[CartesianPosLabel, str]] = ("x", "y", "z")
1689
1700
  """ Coordinate labels of geocentric earth location data (typically shape 3 and 'x', 'y', 'z')"""
1690
1701
 
1702
+ # Station position variable - required
1703
+ STATION_POSITION: Data[tuple[StationName], LocationArray] = None
1704
+ """ Position of the weather station """
1705
+
1691
1706
  # Data variables (all optional)
1692
1707
  H2O: Optional[
1693
1708
  Data[
@@ -1766,8 +1781,6 @@ class WeatherXds:
1766
1781
  ]
1767
1782
  ] = None
1768
1783
  """ Average wind speed """
1769
- STATION_POSITION: Optional[Data[tuple[StationName], LocationArray]] = None
1770
- """ Station position """
1771
1784
 
1772
1785
  # Attributes
1773
1786
  type: Attr[Literal["weather"]] = "weather"
@@ -1883,7 +1896,9 @@ class SystemCalibrationXds:
1883
1896
 
1884
1897
  # Coordinates
1885
1898
  antenna_name: Coordof[AntennaNameArray]
1886
- """ Antenna identifier """
1899
+ """ Antenna name """
1900
+ station_name: Coord[AntennaName, str]
1901
+ """ Name of the station pad (relevant to arrays with moving antennas). """
1887
1902
  receptor_label: Coord[ReceptorLabel, str]
1888
1903
  """ Names of receptors """
1889
1904
  polarization_type: Coord[tuple[AntennaName, ReceptorLabel], str]
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xradio
3
- Version: 0.0.50
3
+ Version: 0.0.51
4
4
  Summary: Xarray Radio Astronomy Data IO
5
- Author-email: Jan-Willem Steeb <jsteeb@nrao.edu>
5
+ Author-email: Jan-Willem Steeb <jsteeb@nrao.edu>, Federico Montesino Pouzols <pouzols@eso.edu>, Dave Mehringer <dmehring@nrao.edu>, Peter Wortmann <peter.wortmann@skao.int>
6
6
  License: BSD 3-Clause License
7
7
 
8
8
  All works in this repository are copyrighted 2024.
@@ -43,7 +43,7 @@ License-File: LICENSE.txt
43
43
  Requires-Dist: astropy
44
44
  Requires-Dist: dask
45
45
  Requires-Dist: distributed
46
- Requires-Dist: toolviper
46
+ Requires-Dist: toolviper>=0.0.11
47
47
  Requires-Dist: numba>=0.57.0
48
48
  Requires-Dist: numpy
49
49
  Requires-Dist: pytest
@@ -79,7 +79,13 @@ Dynamic: license-file
79
79
  # xradio
80
80
  Xarray Radio Astronomy Data IO is still in development.
81
81
 
82
- [![Python 3.9 3.10 3.11 3.12](https://img.shields.io/badge/python-3.9%20%7C%203.10%20%7C%203.11%203.12-blue)](https://www.python.org/downloads/release/python-380/)
82
+ [![Python 3.11 3.12 3.13](https://img.shields.io/badge/python-3.11%20%7C%203.12%20%7C%203.13-blue)](https://www.python.org/downloads/release/python-3130/)
83
+ ![Linux Tests](https://github.com/casangi/xradio/actions/workflows/python-testing-linux.yml/badge.svg?branch=main)
84
+ ![macOS Tests](https://github.com/casangi/xradio/actions/workflows/python-testing-macos.yml/badge.svg?branch=main)
85
+ ![ipynb Tests](https://github.com/casangi/xradio/actions/workflows/run-ipynb.yml/badge.svg?branch=main)
86
+ [![Coverage](https://codecov.io/gh/casangi/xradio/branch/main/graph/badge.svg)](https://codecov.io/gh/casangi/xradio/branch/main/xradio)
87
+ [![Documentation Status](https://readthedocs.org/projects/xradio/badge/?version=latest)](https://xradio.readthedocs.io)
88
+ [![Version Status](https://img.shields.io/pypi/v/xradio.svg)](https://pypi.python.org/pypi/xradio/)
83
89
 
84
90
  # Installing
85
91
  It is recommended to use the conda environment manager from [miniforge](https://github.com/conda-forge/miniforge) to create a clean, self-contained runtime where XRADIO and all its dependencies can be installed:
@@ -1,7 +1,7 @@
1
1
  astropy
2
2
  dask
3
3
  distributed
4
- toolviper
4
+ toolviper>=0.0.11
5
5
  numba>=0.57.0
6
6
  numpy
7
7
  pytest
xradio-0.0.50/README.md DELETED
@@ -1,21 +0,0 @@
1
- # xradio
2
- Xarray Radio Astronomy Data IO is still in development.
3
-
4
- [![Python 3.9 3.10 3.11 3.12](https://img.shields.io/badge/python-3.9%20%7C%203.10%20%7C%203.11%203.12-blue)](https://www.python.org/downloads/release/python-380/)
5
-
6
- # Installing
7
- It is recommended to use the conda environment manager from [miniforge](https://github.com/conda-forge/miniforge) to create a clean, self-contained runtime where XRADIO and all its dependencies can be installed:
8
- ```sh
9
- conda create --name xradio python=3.12 --no-default-packages
10
- conda activate xradio
11
- ```
12
- > 📝 On macOS it is required to pre-install `python-casacore` using `conda install -c conda-forge python-casacore`.
13
-
14
- XRADIO can now be installed using:
15
- ```sh
16
- pip install xradio
17
- ```
18
- This will also install the minimal dependencies for XRADIO. To install the minimal dependencies and the interactive components (JupyterLab) use:
19
- ```sh
20
- pip install "xradio[interactive]"
21
- ```
File without changes
File without changes
File without changes
File without changes