xradio 0.0.36__tar.gz → 0.0.37__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 (79) hide show
  1. {xradio-0.0.36/src/xradio.egg-info → xradio-0.0.37}/PKG-INFO +1 -1
  2. {xradio-0.0.36 → xradio-0.0.37}/pyproject.toml +1 -1
  3. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_vis_utils/_ms/conversion.py +45 -27
  4. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_vis_utils/_ms/create_antenna_xds.py +4 -1
  5. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_vis_utils/_ms/create_field_and_source_xds.py +7 -3
  6. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_vis_utils/_ms/msv4_sub_xdss.py +18 -11
  7. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/read_processing_set.py +1 -1
  8. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/schema.py +278 -99
  9. {xradio-0.0.36 → xradio-0.0.37/src/xradio.egg-info}/PKG-INFO +1 -1
  10. {xradio-0.0.36 → xradio-0.0.37}/LICENSE.txt +0 -0
  11. {xradio-0.0.36 → xradio-0.0.37}/MANIFEST.in +0 -0
  12. {xradio-0.0.36 → xradio-0.0.37}/README.md +0 -0
  13. {xradio-0.0.36 → xradio-0.0.37}/setup.cfg +0 -0
  14. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/__init__.py +0 -0
  15. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/_utils/__init__.py +0 -0
  16. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/_utils/_casacore/tables.py +0 -0
  17. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/_utils/common.py +0 -0
  18. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/_utils/list_and_array.py +0 -0
  19. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/_utils/schema.py +0 -0
  20. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/_utils/zarr/__init__.py +0 -0
  21. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/_utils/zarr/common.py +0 -0
  22. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/image/__init__.py +0 -0
  23. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/image/_util/__init__.py +0 -0
  24. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/image/_util/_casacore/__init__.py +0 -0
  25. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/image/_util/_casacore/common.py +0 -0
  26. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/image/_util/_casacore/xds_from_casacore.py +0 -0
  27. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/image/_util/_casacore/xds_to_casacore.py +0 -0
  28. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/image/_util/_fits/xds_from_fits.py +0 -0
  29. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/image/_util/_zarr/common.py +0 -0
  30. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/image/_util/_zarr/xds_from_zarr.py +0 -0
  31. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/image/_util/_zarr/xds_to_zarr.py +0 -0
  32. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/image/_util/_zarr/zarr_low_level.py +0 -0
  33. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/image/_util/casacore.py +0 -0
  34. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/image/_util/common.py +0 -0
  35. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/image/_util/fits.py +0 -0
  36. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/image/_util/image_factory.py +0 -0
  37. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/image/_util/zarr.py +0 -0
  38. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/image/image.py +0 -0
  39. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/schema/__init__.py +0 -0
  40. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/schema/bases.py +0 -0
  41. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/schema/check.py +0 -0
  42. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/schema/dataclass.py +0 -0
  43. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/schema/metamodel.py +0 -0
  44. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/schema/typing.py +0 -0
  45. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/__init__.py +0 -0
  46. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_processing_set.py +0 -0
  47. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_vis_utils/__init__.py +0 -0
  48. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_vis_utils/_ms/_tables/load.py +0 -0
  49. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_vis_utils/_ms/_tables/load_main_table.py +0 -0
  50. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_vis_utils/_ms/_tables/read.py +0 -0
  51. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_vis_utils/_ms/_tables/read_main_table.py +0 -0
  52. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_vis_utils/_ms/_tables/read_subtables.py +0 -0
  53. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_vis_utils/_ms/_tables/table_query.py +0 -0
  54. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_vis_utils/_ms/_tables/write.py +0 -0
  55. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_vis_utils/_ms/_tables/write_exp_api.py +0 -0
  56. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_vis_utils/_ms/chunks.py +0 -0
  57. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_vis_utils/_ms/descr.py +0 -0
  58. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_vis_utils/_ms/msv2_msv3.py +0 -0
  59. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_vis_utils/_ms/msv2_to_msv4_meta.py +0 -0
  60. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_vis_utils/_ms/msv4_infos.py +0 -0
  61. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_vis_utils/_ms/optimised_functions.py +0 -0
  62. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_vis_utils/_ms/partition_queries.py +0 -0
  63. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_vis_utils/_ms/partitions.py +0 -0
  64. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_vis_utils/_ms/subtables.py +0 -0
  65. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_vis_utils/_utils/cds.py +0 -0
  66. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_vis_utils/_utils/partition_attrs.py +0 -0
  67. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_vis_utils/_utils/stokes_types.py +0 -0
  68. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_vis_utils/_utils/xds_helper.py +0 -0
  69. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_vis_utils/_zarr/encoding.py +0 -0
  70. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_vis_utils/_zarr/read.py +0 -0
  71. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_vis_utils/_zarr/write.py +0 -0
  72. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_vis_utils/ms.py +0 -0
  73. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/_vis_utils/zarr.py +0 -0
  74. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/convert_msv2_to_processing_set.py +0 -0
  75. {xradio-0.0.36 → xradio-0.0.37}/src/xradio/vis/load_processing_set.py +0 -0
  76. {xradio-0.0.36 → xradio-0.0.37}/src/xradio.egg-info/SOURCES.txt +0 -0
  77. {xradio-0.0.36 → xradio-0.0.37}/src/xradio.egg-info/dependency_links.txt +0 -0
  78. {xradio-0.0.36 → xradio-0.0.37}/src/xradio.egg-info/requires.txt +0 -0
  79. {xradio-0.0.36 → xradio-0.0.37}/src/xradio.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: xradio
3
- Version: 0.0.36
3
+ Version: 0.0.37
4
4
  Summary: Xarray Radio Astronomy Data IO
5
5
  Author-email: Jan-Willem Steeb <jsteeb@nrao.edu>
6
6
  License: BSD 3-Clause License
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "xradio"
3
- version = "0.0.36"
3
+ version = "0.0.37"
4
4
  description = " Xarray Radio Astronomy Data IO"
5
5
  authors = [
6
6
  {name = "Jan-Willem Steeb", email="jsteeb@nrao.edu"},
@@ -80,7 +80,7 @@ def check_chunksize(chunksize: dict, xds_type: str) -> None:
80
80
  allowed_dims = [
81
81
  "time",
82
82
  "baseline_id",
83
- "antenna_id",
83
+ "antenna_name",
84
84
  "frequency",
85
85
  "polarization",
86
86
  ]
@@ -138,7 +138,7 @@ def mem_chunksize_to_dict_main(chunksize: float, xds: xr.Dataset) -> Dict[str, i
138
138
  It presently relies on the logic of mem_chunksize_to_dict_main_balanced() to find a
139
139
  balanced list of dimension sizes for the chunks
140
140
 
141
- Assumes these relevant dims: (time, antenna_id/baseline_id, frequency,
141
+ Assumes these relevant dims: (time, antenna_name/baseline_id, frequency,
142
142
  polarization).
143
143
  """
144
144
 
@@ -149,11 +149,11 @@ def mem_chunksize_to_dict_main(chunksize: float, xds: xr.Dataset) -> Dict[str, i
149
149
  "Cannot calculate chunk sizes when memory bound ({chunksize}) does not even allow all polarizations in one chunk"
150
150
  )
151
151
 
152
- baseline_or_antenna_id = find_baseline_or_antenna_var(xds)
153
- total_size = calc_used_gb(xds.sizes, baseline_or_antenna_id, sizeof_vis)
152
+ baseline_or_antenna_name = find_baseline_or_antenna_var(xds)
153
+ total_size = calc_used_gb(xds.sizes, baseline_or_antenna_name, sizeof_vis)
154
154
 
155
155
  ratio = chunksize / total_size
156
- chunked_dims = ["time", baseline_or_antenna_id, "frequency", "polarization"]
156
+ chunked_dims = ["time", baseline_or_antenna_name, "frequency", "polarization"]
157
157
  if ratio >= 1:
158
158
  result = {dim: xds.sizes[dim] for dim in chunked_dims}
159
159
  logger.debug(
@@ -162,14 +162,17 @@ def mem_chunksize_to_dict_main(chunksize: float, xds: xr.Dataset) -> Dict[str, i
162
162
  else:
163
163
  xds_dim_sizes = {k: xds.sizes[k] for k in chunked_dims}
164
164
  result = mem_chunksize_to_dict_main_balanced(
165
- chunksize, xds_dim_sizes, baseline_or_antenna_id, sizeof_vis
165
+ chunksize, xds_dim_sizes, baseline_or_antenna_name, sizeof_vis
166
166
  )
167
167
 
168
168
  return result
169
169
 
170
170
 
171
171
  def mem_chunksize_to_dict_main_balanced(
172
- chunksize: float, xds_dim_sizes: dict, baseline_or_antenna_id: str, sizeof_vis: int
172
+ chunksize: float,
173
+ xds_dim_sizes: dict,
174
+ baseline_or_antenna_name: str,
175
+ sizeof_vis: int,
173
176
  ) -> Dict[str, int]:
174
177
  """
175
178
  Assumes the ratio is <1 and all pols can fit in memory (from
@@ -236,7 +239,7 @@ def mem_chunksize_to_dict_main_balanced(
236
239
  dim_chunksizes[idx] += int_delta
237
240
  used = np.prod(dim_chunksizes) * sizeof_vis / GiBYTES_TO_BYTES
238
241
 
239
- chunked_dim_names = ["time", baseline_or_antenna_id, "frequency", "polarization"]
242
+ chunked_dim_names = ["time", baseline_or_antenna_name, "frequency", "polarization"]
240
243
  dim_chunksizes_int = [int(v) for v in dim_chunksizes]
241
244
  result = dict(zip(chunked_dim_names, dim_chunksizes_int))
242
245
 
@@ -314,11 +317,11 @@ def mem_chunksize_to_dict_pointing(chunksize: float, xds: xr.Dataset) -> Dict[st
314
317
 
315
318
  def find_baseline_or_antenna_var(xds: xr.Dataset) -> str:
316
319
  if "baseline_id" in xds.coords:
317
- baseline_or_antenna_id = "baseline_id"
318
- elif "antenna_id" in xds.coords:
319
- baseline_or_antenna_id = "antenna_id"
320
+ baseline_or_antenna_name = "baseline_id"
321
+ elif "antenna_name" in xds.coords:
322
+ baseline_or_antenna_name = "antenna_name"
320
323
 
321
- return baseline_or_antenna_id
324
+ return baseline_or_antenna_name
322
325
 
323
326
 
324
327
  def itemsize_vis_spec(xds: xr.Dataset) -> int:
@@ -352,11 +355,11 @@ def itemsize_pointing_spec(xds: xr.Dataset) -> int:
352
355
 
353
356
 
354
357
  def calc_used_gb(
355
- chunksizes: dict, baseline_or_antenna_id: str, sizeof_vis: int
358
+ chunksizes: dict, baseline_or_antenna_name: str, sizeof_vis: int
356
359
  ) -> float:
357
360
  return (
358
361
  chunksizes["time"]
359
- * chunksizes[baseline_or_antenna_id]
362
+ * chunksizes[baseline_or_antenna_name]
360
363
  * chunksizes["frequency"]
361
364
  * chunksizes["polarization"]
362
365
  * sizeof_vis
@@ -734,7 +737,6 @@ def convert_and_write_partition(
734
737
  """
735
738
 
736
739
  taql_where = create_taql_query(partition_info)
737
- # print("taql_where", taql_where)
738
740
  ddi = partition_info["DATA_DESC_ID"][0]
739
741
  obs_mode = str(partition_info["OBS_MODE"][0])
740
742
 
@@ -877,7 +879,8 @@ def convert_and_write_partition(
877
879
  )
878
880
 
879
881
  # Change antenna_ids to antenna_names
880
- xds = antenna_ids_to_names(xds, ant_xds)
882
+ xds = antenna_ids_to_names(xds, ant_xds, is_single_dish)
883
+ ant_xds_name_ids = ant_xds["antenna_name"].set_xindex("antenna_id")
881
884
  ant_xds = ant_xds.drop_vars(
882
885
  "antenna_id"
883
886
  ) # No longer needed after converting to name.
@@ -897,7 +900,7 @@ def convert_and_write_partition(
897
900
  else:
898
901
  pointing_interp_time = None
899
902
  pointing_xds = create_pointing_xds(
900
- in_file, time_min_max, pointing_interp_time
903
+ in_file, ant_xds_name_ids, time_min_max, pointing_interp_time
901
904
  )
902
905
  pointing_chunksize = parse_chunksize(
903
906
  pointing_chunksize, "pointing", pointing_xds
@@ -953,7 +956,6 @@ def convert_and_write_partition(
953
956
 
954
957
  # Fix UVW frame
955
958
  # From CASA fixvis docs: clean and the im tool ignore the reference frame claimed by the UVW column (it is often mislabelled 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 center. calcuvw does not yet force the UVW column and field centers to use the same reference frame! Blank = use the phase tracking frame of vis.
956
- # print('##################',field_and_source_xds)
957
959
  if is_single_dish:
958
960
  xds.UVW.attrs["frame"] = field_and_source_xds[
959
961
  "FIELD_REFERENCE_CENTER"
@@ -1037,17 +1039,19 @@ def convert_and_write_partition(
1037
1039
  # logger.info("Saved ms_v4 " + file_name + " in " + str(time.time() - start_with) + "s")
1038
1040
 
1039
1041
 
1040
- def antenna_ids_to_names(xds, ant_xds):
1042
+ def antenna_ids_to_names(
1043
+ xds: xr.Dataset, ant_xds: xr.Dataset, is_single_dish: bool
1044
+ ) -> xr.Dataset:
1041
1045
  ant_xds = ant_xds.set_xindex(
1042
1046
  "antenna_id"
1043
1047
  ) # Allows for non-dimension coordinate selection.
1044
1048
 
1045
- if "baseline_antenna1_id" in xds: # Interferometer
1046
- xds["baseline_antenna1_id"] = ant_xds["antenna_name"].sel(
1047
- antenna_id=xds["baseline_antenna1_id"]
1049
+ if not is_single_dish: # Interferometer
1050
+ xds["baseline_antenna1_id"].data = ant_xds["antenna_name"].sel(
1051
+ antenna_id=xds["baseline_antenna1_id"].data
1048
1052
  )
1049
- xds["baseline_antenna2_id"] = ant_xds["antenna_name"].sel(
1050
- antenna_id=xds["baseline_antenna2_id"]
1053
+ xds["baseline_antenna2_id"].data = ant_xds["antenna_name"].sel(
1054
+ antenna_id=xds["baseline_antenna2_id"].data
1051
1055
  )
1052
1056
  xds = xds.rename(
1053
1057
  {
@@ -1055,9 +1059,23 @@ def antenna_ids_to_names(xds, ant_xds):
1055
1059
  "baseline_antenna2_id": "baseline_antenna2_name",
1056
1060
  }
1057
1061
  )
1058
- else: # Single Dish
1059
- xds["antenna_id"] = ant_xds["antenna_name"].sel(antenna_id=xds["antenna_id"])
1060
- xds = xds.rename({"antenna_id": "antenna_name"})
1062
+ else:
1063
+ xds["baseline_id"] = ant_xds["antenna_name"].sel(antenna_id=xds["baseline_id"])
1064
+ unwanted_coords_from_ant_xds = [
1065
+ "antenna_id",
1066
+ "antenna_name",
1067
+ "mount",
1068
+ "station",
1069
+ ]
1070
+ for unwanted_coord in unwanted_coords_from_ant_xds:
1071
+ xds = xds.drop_vars(unwanted_coord)
1072
+ xds = xds.rename({"baseline_id": "antenna_name"})
1073
+
1074
+ # drop more vars that seem unwanted in main_sd_xds, but there shouuld be a better way
1075
+ # of not creating them in the first place
1076
+ unwanted_coords_sd = ["baseline_antenna1_id", "baseline_antenna2_id"]
1077
+ for unwanted_coord in unwanted_coords_sd:
1078
+ xds = xds.drop_vars(unwanted_coord)
1061
1079
 
1062
1080
  return xds
1063
1081
 
@@ -127,7 +127,6 @@ def extract_antenna_info(
127
127
  ) # Make sure the antenna_id order is correct.
128
128
 
129
129
  # ['OFFSET', 'POSITION', 'DISH_DIAMETER', 'FLAG_ROW', 'MOUNT', 'NAME', 'STATION']
130
- ant_xds = xr.Dataset()
131
130
  ant_xds = ant_xds.assign_coords({"cartesian_pos_label": ["x", "y", "z"]})
132
131
 
133
132
  ant_xds = convert_generic_xds_to_xradio_schema(
@@ -254,9 +253,13 @@ def extract_feed_info(
254
253
 
255
254
  # print('ant_xds["ANTENNA_FEED_OFFSET"]',ant_xds["ANTENNA_FEED_OFFSET"].data)
256
255
  # print('generic_feed_xds["POSITION"].data',generic_feed_xds["POSITION"].data)
256
+ feed_offset_attrs = ant_xds["ANTENNA_FEED_OFFSET"].attrs
257
257
  ant_xds["ANTENNA_FEED_OFFSET"] = (
258
258
  ant_xds["ANTENNA_FEED_OFFSET"] + generic_feed_xds["POSITION"].data
259
259
  )
260
+ # recover attrs after arithmetic operation
261
+ ant_xds["ANTENNA_FEED_OFFSET"].attrs.update(feed_offset_attrs)
262
+
260
263
  coords = {}
261
264
  # coords["receptor_label"] = "pol_" + np.arange(ant_xds.sizes["receptor_label"]).astype(str) #Works on laptop but fails in github test runner.
262
265
  coords["receptor_label"] = np.array(
@@ -30,7 +30,7 @@ def create_field_and_source_xds(
30
30
  is_single_dish: bool,
31
31
  time_min_max: Tuple[np.float64, np.float64],
32
32
  ephemeris_interp_time: Union[xr.DataArray, None] = None,
33
- ):
33
+ ) -> tuple[xr.Dataset, int]:
34
34
  """
35
35
  Create a field and source xarray dataset (xds) from the given input file, field ID, and spectral window ID.
36
36
  Data is extracted from the FIELD and SOURCE tables and if there is ephemeris data, it is also extracted.
@@ -57,11 +57,13 @@ def create_field_and_source_xds(
57
57
  -------
58
58
  field_and_source_xds : xr.Dataset
59
59
  The xarray dataset containing the field and source information.
60
+ num_lines : int
61
+ Sum of num_lines for all unique sources.
60
62
  """
61
63
 
62
64
  start_time = time.time()
63
65
 
64
- field_and_source_xds = xr.Dataset()
66
+ field_and_source_xds = xr.Dataset(attrs={"type": "field_and_source"})
65
67
 
66
68
  field_and_source_xds, ephemeris_path, ephemeris_table_name, source_id = (
67
69
  extract_field_info_and_check_ephemeris(
@@ -433,7 +435,9 @@ def extract_ephemeris_info(
433
435
  return xds
434
436
 
435
437
 
436
- def extract_source_info(xds, path, source_id, spectral_window_id):
438
+ def extract_source_info(
439
+ xds: xr.Dataset, path: str, source_id: int, spectral_window_id: int
440
+ ) -> tuple[xr.Dataset, int]:
437
441
  """
438
442
  Extracts source information from the given path and adds it to the xarray dataset.
439
443
 
@@ -121,11 +121,13 @@ def create_weather_xds(in_file: str):
121
121
  # ['ANTENNA_ID', 'TIME', 'INTERVAL', 'H2O', 'IONOS_ELECTRON',
122
122
  # 'PRESSURE', 'REL_HUMIDITY', 'TEMPERATURE', 'DEW_POINT',
123
123
  # 'WIND_DIRECTION', 'WIND_SPEED']
124
- weather_xds = xr.Dataset()
125
-
124
+ weather_xds = xr.Dataset(attrs={"type": "weather"})
125
+ time_attrs = column_description_casacore_to_msv4_measure(
126
+ weather_column_description["TIME"]
127
+ )
126
128
  coords = {
127
129
  "station_id": generic_weather_xds["STATION_ID"].data,
128
- "time": generic_weather_xds["TIME"].data,
130
+ "time": ("time", generic_weather_xds["TIME"].data, time_attrs),
129
131
  }
130
132
  for key in generic_weather_xds:
131
133
  msv4_measure = column_description_casacore_to_msv4_measure(
@@ -181,6 +183,7 @@ def create_weather_xds(in_file: str):
181
183
 
182
184
  def create_pointing_xds(
183
185
  in_file: str,
186
+ ant_xds_name_ids: xr.DataArray,
184
187
  time_min_max: Union[Tuple[np.float64, np.float64], None],
185
188
  interp_time: Union[xr.DataArray, None] = None,
186
189
  ) -> xr.Dataset:
@@ -194,6 +197,8 @@ def create_pointing_xds(
194
197
  ----------
195
198
  in_file : str
196
199
  Input MS name.
200
+ ant_xds_name_ids : xr.Dataset
201
+ antenna_name data array from antenna_xds, with name/id information
197
202
  time_min_max : tuple
198
203
  min / max times values to constrain loading (from the TIME column)
199
204
  interp_time : Union[xr.DataArray, None] (Default value = None)
@@ -220,19 +225,19 @@ def create_pointing_xds(
220
225
  # "on_source": "ON_SOURCE", # removed
221
226
  "OVER_THE_TOP": "OVER_THE_TOP",
222
227
  }
223
- time_ant_dims = ["time", "antenna_id"]
228
+ time_ant_dims = ["time", "antenna_name"]
224
229
  time_ant_dir_dims = time_ant_dims + ["sky_dir_label"]
225
230
  data_variable_dims = {
226
- # "name": ["time", "antenna_id"], # removed
227
- # "time_origin": ["time", "antenna_id"], # removed?
231
+ # "name": ["time", "antenna_name"], # removed
232
+ # "time_origin": ["time", "antenna_name"], # removed?
228
233
  "DIRECTION": time_ant_dir_dims,
229
234
  "ENCODER": time_ant_dir_dims,
230
235
  "TARGET": time_ant_dir_dims,
231
236
  "POINTING_OFFSET": time_ant_dir_dims,
232
237
  "SOURCE_OFFSET": time_ant_dir_dims,
233
- # "pointing_model_id": ["time", "antenna_id"], # removed
234
- # "tracking": ["time", "antenna_id"], # => attribute
235
- # "on_source": ["time", "antenna_id"], # removed
238
+ # "pointing_model_id": ["time", "antenna_name"], # removed
239
+ # "tracking": ["time", "antenna_name"], # => attribute
240
+ # "on_source": ["time", "antenna_name"], # removed
236
241
  "OVER_THE_TOP": time_ant_dims,
237
242
  }
238
243
  # Unused here
@@ -263,7 +268,7 @@ def create_pointing_xds(
263
268
  "ctds_attrs"
264
269
  ]["column_descriptions"]
265
270
 
266
- pointing_xds = xr.Dataset()
271
+ pointing_xds = xr.Dataset(attrs={"type": "pointing"})
267
272
  for key in generic_pointing_xds:
268
273
  if key in to_new_data_variable_names:
269
274
  data_var_name = to_new_data_variable_names[key]
@@ -312,7 +317,9 @@ def create_pointing_xds(
312
317
 
313
318
  coords = {
314
319
  "time": generic_pointing_xds["TIME"].values,
315
- "antenna_id": np.arange(generic_pointing_xds.sizes["ANTENNA_ID"]),
320
+ "antenna_name": ant_xds_name_ids.sel(
321
+ antenna_id=generic_pointing_xds["ANTENNA_ID"]
322
+ ).data,
316
323
  "sky_dir_label": ["ra", "dec"],
317
324
  }
318
325
  pointing_xds = pointing_xds.assign_coords(coords)
@@ -38,7 +38,7 @@ def read_processing_set(
38
38
  data_groups = xds.attrs["data_groups"]
39
39
 
40
40
  if (obs_modes is None) or (
41
- xds.attrs["partition_info"]["obs_mode"] in obs_modes
41
+ bool(set(xds.attrs["partition_info"]["obs_mode"]).intersection(obs_modes))
42
42
  ):
43
43
  sub_xds_dict, field_and_source_xds_dict = _read_sub_xds(
44
44
  ms_store, file_system=file_system, data_groups=data_groups
@@ -12,14 +12,16 @@ import numpy
12
12
  # Dimensions
13
13
  Time = Literal["time"]
14
14
  """ Observation time dimension """
15
- AntennaId = Literal["antenna_id"]
16
- """ Antenna ID dimension """
15
+ AntennaName = Literal["antenna_name"]
16
+ """ Antenna name dimension """
17
17
  StationId = Literal["station_id"]
18
18
  """ Station ID dimension """
19
19
  ReceptorId = Literal["receptor_id"]
20
20
  """ Receptor ID dimension """
21
- ReceptorName = Literal["receptor_label"]
22
- """ Receptor name dimension """
21
+ ReceptorLabel = Literal["receptor_label"]
22
+ """ Receptor label dimension """
23
+ ToneLabel = Literal["tone_label"]
24
+ """ Tone label dimension """
23
25
  BaselineId = Literal["baseline_id"]
24
26
  """ Baseline ID dimension """
25
27
  Frequency = Literal["frequency"]
@@ -40,8 +42,12 @@ EllipsoidPosLabel = Literal["ellipsoid_pos_label"]
40
42
  """ Coordinate labels of geodetic earth location data (typically shape 3 and 'lon', 'lat', 'height')"""
41
43
  CartesianPosLabel = Literal["cartesian_pos_label"]
42
44
  """ Coordinate labels of geocentric earth location data (typically shape 3 and 'x', 'y', 'z')"""
45
+ TimePhaseCal = Literal["time_phase_cal"]
46
+ """ Coordinate label for VLBI-specific phase cal time axis """
43
47
  TimePolynomial = Literal["time_polynomial"]
44
48
  """ For data that is represented as variable in time using Taylor expansion """
49
+ PolyTerm = Literal["poly_term"]
50
+ """ Polynomial term used in VLBI GAIN_CURVE """
45
51
  LineLabel = Literal["line_label"]
46
52
  """ Line labels (for line names and variables). """
47
53
 
@@ -276,6 +282,11 @@ class FieldSourceXds:
276
282
  """
277
283
  is_ephemeris: Attr[bool] = False
278
284
 
285
+ type: Attr[str] = "field_and_source"
286
+ """
287
+ Type of dataset.
288
+ """
289
+
279
290
  # --- Optional coordinates ---
280
291
  sky_dir_label: Optional[Coord[SkyDirLabel, str]] = ("ra", "dec")
281
292
  """ Coordinate labels of sky directions (typically shape 2 and 'ra', 'dec') """
@@ -319,6 +330,22 @@ class EarthLocationArray:
319
330
  """
320
331
 
321
332
 
333
+ @dict_schema
334
+ class PartitionInfoDict:
335
+ # spectral_window_id: missing / remove for good?
336
+ spectral_window_name: str
337
+ # field_id: missing / probably remove for good?
338
+ field_name: list[str]
339
+ # source_id: mising / remove for good?
340
+ line_name: list[str]
341
+ scan_number: list[int]
342
+ source_name: list[str]
343
+ polarization_setup: list[str]
344
+ num_lines: int
345
+ obs_mode: list[str]
346
+ taql: Optional[str]
347
+
348
+
322
349
  @dict_schema
323
350
  class ObservationInfoDict:
324
351
  observer: list
@@ -366,13 +393,22 @@ class BaselineArray:
366
393
 
367
394
 
368
395
  @xarray_dataarray_schema
369
- class BaselineAntennaArray:
370
- data: Data[BaselineId, Union[numpy.int64, numpy.int32]]
371
- """
372
- Antenna id for an antenna in a baseline. Maps to ``attrs['antenna_xds'].antenna_id``
373
- in :py:class:`VisibilityXds`
374
- """
375
- long_name: Optional[Attr[str]] = "Baseline Antenna ID"
396
+ class BaselineAntennaNameArray:
397
+ """Array of antenna_name by baseline_id, as used in main_xds and main_sd_xds
398
+ (antenna_name by baseline_id dim"""
399
+
400
+ data: Data[BaselineId, str]
401
+ """Unique id for each baseline."""
402
+ long_name: Optional[Attr[str]] = "Antenna name by baseline_id"
403
+
404
+
405
+ @xarray_dataarray_schema
406
+ class AntennaNameArray:
407
+ """TODO: documentation"""
408
+
409
+ data: Data[AntennaName, str]
410
+ """Unique name for each antenna(_station)."""
411
+ long_name: Optional[Attr[str]] = "Antenna name"
376
412
 
377
413
 
378
414
  @xarray_dataset_schema
@@ -485,17 +521,15 @@ class SpectrumArray:
485
521
  """Definition of xr.DataArray for SPECTRUM data (single dish)"""
486
522
 
487
523
  data: Data[
488
- tuple[Time, BaselineId, Frequency, Polarization],
524
+ tuple[Time, AntennaName, Frequency, Polarization],
489
525
  Union[numpy.float64, numpy.float32, numpy.float16],
490
526
  ]
491
- time: Coord[tuple[()], TimeCoordArray]
492
527
 
493
- # in the spreadsheet this is antenna_id:
494
- # antenna_id: Coord[AntennaId, Union[int, numpy.int32]]
495
- baseline_id: Coord[tuple[()], BaselineArray]
528
+ time: Coordof[TimeCoordArray]
529
+ antenna_name: Coordof[AntennaNameArray]
530
+ frequency: Coordof[FrequencyArray]
531
+ polarization: Coordof[PolarizationArray]
496
532
 
497
- polarization: Coord[tuple[()], PolarizationArray]
498
- frequency: Coord[tuple[()], FrequencyArray]
499
533
  field_and_source_xds: Attr[FieldSourceXds]
500
534
  long_name: Optional[Attr[str]] = "Spectrum values"
501
535
  """ Long-form name to use for axis. Should be ``"Spectrum values"``"""
@@ -515,11 +549,13 @@ class FlagArray:
515
549
  tuple[Time, BaselineId, Frequency, Polarization],
516
550
  tuple[Time, BaselineId, Frequency],
517
551
  tuple[Time, BaselineId],
552
+ tuple[Time, AntennaName, Frequency, Polarization], # SD
518
553
  ],
519
554
  bool,
520
555
  ]
521
556
  time: Coordof[TimeCoordArray]
522
- baseline_id: Coordof[BaselineArray]
557
+ baseline_id: Optional[Coordof[BaselineArray]] # Only IF
558
+ antenna_name: Optional[Coordof[AntennaNameArray]] # Only SD
523
559
  frequency: Coordof[FrequencyArray]
524
560
  polarization: Optional[Coordof[PolarizationArray]] = None
525
561
  long_name: Optional[Attr[str]] = "Visibility flags"
@@ -540,12 +576,14 @@ class WeightArray:
540
576
  tuple[Time, BaselineId, Frequency, Polarization],
541
577
  tuple[Time, BaselineId, Frequency],
542
578
  tuple[Time, BaselineId],
579
+ tuple[Time, AntennaName, Frequency, Polarization], # SD
543
580
  ],
544
581
  Union[numpy.float16, numpy.float32, numpy.float64],
545
582
  ]
546
583
  """Visibility weights"""
547
584
  time: Coordof[TimeCoordArray]
548
- baseline_id: Coordof[BaselineArray]
585
+ baseline_id: Optional[Coordof[BaselineArray]] # Only IF
586
+ antenna_name: Optional[Coordof[AntennaNameArray]] # Only SD
549
587
  frequency: Optional[Coordof[FrequencyArray]] = None
550
588
  polarization: Optional[Coordof[PolarizationArray]] = None
551
589
  long_name: Optional[Attr[str]] = "Visibility weights"
@@ -586,6 +624,9 @@ class UvwArray:
586
624
  tuple[Time, BaselineId, Frequency, Polarization, UvwLabel],
587
625
  tuple[Time, BaselineId, Frequency, UvwLabel],
588
626
  tuple[Time, BaselineId, UvwLabel],
627
+ tuple[Time, AntennaName, UvwLabel], # SD
628
+ tuple[Time, AntennaName, Frequency, UvwLabel], # SD
629
+ tuple[Time, AntennaName, Frequency, Polarization], # SD
589
630
  ],
590
631
  Union[
591
632
  numpy.float16,
@@ -595,7 +636,8 @@ class UvwArray:
595
636
  ]
596
637
  """Baseline coordinates from ``baseline_antenna2_id`` to ``baseline_antenna1_id``"""
597
638
  time: Coordof[TimeCoordArray]
598
- baseline_id: Coordof[BaselineArray]
639
+ baseline_id: Optional[Coordof[BaselineArray]] # Only IF
640
+ antenna_name: Optional[Coordof[AntennaNameArray]] # Only SD
599
641
  frequency: Optional[Coordof[FrequencyArray]] = None
600
642
  polarization: Optional[Coordof[PolarizationArray]] = None
601
643
  uvw_label: Coordof[UvwLabelArray] = ("u", "v", "w")
@@ -613,12 +655,14 @@ class TimeSamplingArray:
613
655
  tuple[Time, BaselineId, Frequency, Polarization],
614
656
  tuple[Time, BaselineId, Frequency],
615
657
  tuple[Time, BaselineId],
658
+ tuple[Time, AntennaName], # SD
616
659
  ],
617
660
  float,
618
661
  ]
619
662
 
620
663
  time: Coordof[TimeCoordArray]
621
- baseline_id: Coordof[BaselineArray]
664
+ baseline_id: Optional[Coordof[BaselineArray]] # Only IF
665
+ antenna_name: Optional[Coordof[AntennaNameArray]] # Only SD
622
666
  frequency: Optional[Coordof[FrequencyArray]] = None
623
667
  polarization: Optional[Coordof[PolarizationArray]] = None
624
668
 
@@ -667,88 +711,147 @@ class FreqSamplingArray:
667
711
  # Data Sets
668
712
 
669
713
 
670
- @xarray_dataset_schema
671
- class AntennaXdsEmptyWhileRevampedTODO:
672
- """Minimal placeholder so that it shows in the main xds
673
- docs. TODO: update AntennaXds once review moves on
674
- """
675
-
676
- antenna_name: Coord[Literal["antenna_name"], str]
677
- receptor_label: Optional[Coord[ReceptorName, str]]
678
- cartesian_pos_label: Coord[CartesianPosLabel, str]
679
- sky_dir_label: Optional[Coord[SkyDirLabel, str]]
680
- gain_curve_time: Optional[Coord[Literal["gain_curve_time"], numpy.float64]]
681
- poly_term: Optional[Coord[Literal["poly_term"], numpy.int64]]
682
- phase_cal_time: Optional[Coord[Literal["phase_cal_time"], numpy.float64]]
683
- tone_label: Optional[Coord[Literal["tone_label"], numpy.int64]]
684
-
685
-
686
714
  @xarray_dataset_schema
687
715
  class AntennaXds:
688
- # --- Coordinates ---
689
- antenna_id: Coord[AntennaId, Union[int, numpy.int32]]
690
- """Antenna ID"""
691
- name: Coord[AntennaId, str]
692
-
693
- """Antenna name."""
694
- station: Coord[AntennaId, str]
695
- """Name of the station pad (relevant to arrays with moving antennas)."""
696
- antenna_type: Optional[Coord[AntennaId, str]]
697
- """Antenna type.
698
-
699
- Reserved keywords include: (``GROUND-BASED`` - conventional
700
- antennas; ``SPACE-BASED`` - orbiting antennas; ``TRACKING-STN`` - tracking
701
- stations)."""
702
- mount: Coord[AntennaId, str]
703
- """Mount type of the antenna.
704
-
705
- Reserved keywords include: (``EQUATORIAL`` - equatorial mount; ``ALTAZ`` -
706
- azimuth-elevation mount; ``X-Y`` - x-y mount; ``SPACE-HALCA`` - specific
707
- orientation model.)"""
708
- observatory: Optional[Coord[AntennaId, str]]
709
- """Support for VLBI"""
710
- receptor_name: Optional[Coord[ReceptorName, str]]
711
- """Names of receptors"""
712
- cartesian_pos_label: Coord[CartesianPosLabel, str]
713
- """Coordinate dimension of earth location data (typically shape 3 and 'x', 'y', 'z')"""
716
+ # Coordinates
717
+ antenna_name: Coordof[AntennaNameArray]
718
+ """ Antenna name """
719
+ station: Coord[AntennaName, str]
720
+ """ Name of the station pad (relevant to arrays with moving antennas). """
721
+ mount: Coord[AntennaName, str]
722
+ """ Mount type of the antenna. Reserved keywords include: ”EQUATORIAL” - equatorial mount;
723
+ ”ALT-AZ” - azimuth-elevation mount;
724
+ "ALT-AZ+ROTATOR" alt-az mount with feed rotator; introduced for ASKAP dishes;
725
+ "ALT-AZ+NASMYTH-R": Nasmyth mount with receivers at the right-hand side of the cabin. Many high-frequency antennas used for VLBI have such a mount typel;
726
+ "ALT-AZ+NASMYTH-L:: Nasmyth mount with receivers at the left-hand side of the cabin.
727
+ ”X-Y” - x-y mount;
728
+ SPACE-HALCA” - specific orientation model."""
729
+ telescope_name: Optional[Coord[AntennaName, str]]
730
+ """ Useful when data is combined from mutiple arrays for example ACA + ALMA. """
731
+ # TODO: receptor_label, polarization_type, sky_dir_label set as optional
732
+ # for datasets like test_alma_ephemris_mosaic. See also BEAM_OFFSET below.
733
+ receptor_label: Optional[Coord[ReceptorLabel, str]]
734
+ """ Names of receptors """
735
+ polarization_type: Optional[Coord[tuple[AntennaName, ReceptorLabel], str]]
736
+ """ Polarization type to which each receptor responds (e.g. ”R”,”L”,”X” or ”Y”).
737
+ This is the receptor polarization type as recorded in the final correlated data (e.g. ”RR”); i.e.
738
+ as measured after all polarization combiners. ['X','Y'], ['R','L'] """
739
+ cartesian_pos_label: Optional[Coord[CartesianPosLabel, str]]
740
+ """ (x,y,z) - either cartesian or ellipsoid """
741
+ ellipsoid_pos_label: Optional[Coord[EllipsoidPosLabel, str]]
742
+ """ (lon, lat, dist) - either cartesian or ellipsoid"""
714
743
  sky_dir_label: Optional[Coord[SkyDirLabel, str]]
715
- """Coordinate dimension of sky coordinate data (possibly shape 2 and 'RA', "Dec")"""
716
-
717
- # --- Data variables ---
718
- ANTENNA_POSITION: Data[AntennaId, EarthLocationArray]
744
+ """ ra, dec """
745
+ time: Optional[Coordof[TimeCoordArray]]
746
+ """ Time for VLBI phase cal"""
747
+ time_phase_cal: Optional[Coord[TimePhaseCal, numpy.float64]]
748
+ """ Time for VLBI phase cal"""
749
+ tone_label: Optional[Coord[ToneLabel, str]]
750
+ """ ? """
751
+ gain_curve_type: Optional[Coord[AntennaName, str]]
752
+ """ ? """
753
+
754
+ # Data variables
755
+ ANTENNA_POSITION: Data[
756
+ Union[
757
+ tuple[AntennaName, EllipsoidPosLabel], tuple[AntennaName, CartesianPosLabel]
758
+ ],
759
+ QuantityArray,
760
+ ] # EarthLocationArray
719
761
  """
720
762
  In a right-handed frame, X towards the intersection of the equator and
721
763
  the Greenwich meridian, Z towards the pole.
722
764
  """
723
- ANTENNA_FEED_OFFSET: Data[tuple[AntennaId, CartesianPosLabel], QuantityArray]
765
+ ANTENNA_FEED_OFFSET: Data[
766
+ Union[
767
+ tuple[AntennaName, EllipsoidPosLabel], tuple[AntennaName, CartesianPosLabel]
768
+ ],
769
+ QuantityArray,
770
+ ]
724
771
  """
725
772
  Offset of feed relative to position (``Antenna_Table.offset + Feed_Table.position``).
726
773
  """
727
- ANTENNA_DISH_DIAMETER: Data[AntennaId, QuantityArray]
774
+ ANTENNA_DISH_DIAMETER: Optional[Data[tuple[AntennaName], QuantityArray]]
728
775
  """
729
776
  Nominal diameter of dish, as opposed to the effective diameter.
730
777
  """
731
- BEAM_OFFSET: Optional[Data[AntennaId, SkyCoordArray]]
778
+ ANTENNA_EFFECTIVE_DISH_DIAMETER: Optional[
779
+ Data[tuple[AntennaName, ReceptorLabel, SkyDirLabel], QuantityArray]
780
+ ]
781
+ """ Airy Disk Model .... """
782
+
783
+ # TODO: setting BEAM_OFFSET and RECEPTOR_ANGLE as optional for now, as it
784
+ # is not present in some datasets (example: test_alma_ephemris_mosaic)
785
+ BEAM_OFFSET: Optional[Data[tuple[AntennaName, ReceptorLabel], SkyCoordArray]]
732
786
  """
733
787
  Beam position offset, as defined on the sky but in the antenna
734
788
  reference frame.
735
789
  """
736
- RECEPTOR_ANGLE: Optional[Data[tuple[AntennaId, ReceptorName], QuantityArray]]
790
+ RECEPTOR_ANGLE: Optional[Data[tuple[AntennaName, ReceptorLabel], QuantityArray]]
737
791
  """
738
792
  Polarization reference angle. Converts into parallactic angle in the sky domain.
739
793
  """
740
- FOCUS_LENGTH: Optional[Data[AntennaId, QuantityArray]]
794
+ FOCUS_LENGTH: Optional[Data[tuple[AntennaName], QuantityArray]]
741
795
  """
742
796
  Focus length. As defined along the optical axis of the antenna.
743
797
  """
744
- ARRAY_CENTER: Optional[Data[AntennaId, EarthLocationArray]]
745
- EFFECTIVE_DISH_DIAMETER: Optional[Data[AntennaId, QuantityArray]]
746
798
 
747
- # --- Attributes ---
748
- telescope_name: Optional[Attr[str]]
799
+ GAIN_CURVE: Optional[
800
+ Data[tuple[AntennaName, ReceptorLabel, PolyTerm], numpy.float32]
801
+ ]
802
+ """ VLBI. ? """
803
+ GAIN_CURVE_INTERVAL: Optional[Data[tuple[AntennaName], QuantityArray]]
804
+ """ VLBI. ? """
805
+ GAIN_CURVE_SENSITIVITY: Optional[
806
+ Data[tuple[AntennaName, ReceptorLabel], numpy.float32]
807
+ ]
808
+ """ VLBI. ? """
809
+ PHASE_CAL: Optional[
810
+ Data[
811
+ Union[
812
+ tuple[AntennaName, Time, ReceptorLabel, ToneLabel],
813
+ tuple[AntennaName, TimePhaseCal, ReceptorLabel, ToneLabel],
814
+ ],
815
+ numpy.complex64,
816
+ ]
817
+ ]
818
+ """ VLBI. ? """
819
+ PHASE_CAL_CABLE_CAL: Optional[
820
+ Data[
821
+ Union[tuple[AntennaName, Time], tuple[AntennaName, TimePhaseCal]],
822
+ QuantityArray,
823
+ ]
824
+ ]
825
+ """ VLBI. ? """
826
+ PHASE_CAL_INTERVAL: Optional[
827
+ Data[
828
+ Union[tuple[AntennaName, Time], tuple[AntennaName, TimePhaseCal]],
829
+ QuantityArray,
830
+ ]
831
+ ]
832
+ """ VLBI. ? """
833
+ PHASE_CAL_TONE_FREQUENCY: Optional[
834
+ Data[
835
+ Union[
836
+ tuple[AntennaName, Time, ReceptorLabel, ToneLabel],
837
+ tuple[AntennaName, TimePhaseCal, ReceptorLabel, ToneLabel],
838
+ ],
839
+ QuantityArray,
840
+ ]
841
+ ]
842
+ """ VLBI. ? """
843
+
844
+ # Attributes
845
+ overall_telescope_name: Optional[Attr[str]]
749
846
  """
750
- From MS v2 observation table
847
+ The name of the collection of arrays and dishes that were used for the observation.
848
+ In many instances this will only be a single array or dish. An example of a
849
+ telescope consistening of mutiple arrays and dishes is the EHT. The coordinate
850
+ telescope_name will give the names of the constituent arrays and dishes. From
851
+ MSv2 observation table.
751
852
  """
853
+ relocatable_antennas: Optional[Attr[bool]]
854
+ """ Can the antennas be moved (ALMA, VLA, NOEMA) """
752
855
  type: Attr[str] = "antenna"
753
856
  """
754
857
  Type of dataset. Expected to be ``antenna``
@@ -757,12 +860,42 @@ class AntennaXds:
757
860
 
758
861
  @xarray_dataset_schema
759
862
  class WeatherXds:
760
- """TODO: largely incomplete"""
863
+ """Weather. Contains station positions and time-dependent mean external
864
+ atmosphere and weather information"""
761
865
 
866
+ # Coordinates
867
+ time: Coordof[TimeCoordArray]
868
+ """ Mid-point of the time interval """
762
869
  station_id: Coord[StationId, numpy.int64]
763
870
  """ Station identifier """
764
- time: Coord[Time, numpy.float64]
765
- """ Mid-point of the time interval """
871
+ antenna_name: Optional[Coordof[AntennaNameArray]]
872
+ """ Antenna identifier """
873
+
874
+ # Data variables (all optional)
875
+ H2O: Optional[Data[tuple[StationId, Time], QuantityArray]] = None
876
+ """ Average column density of water """
877
+ IONOS_ELECTRON: Optional[Data[tuple[StationId, Time], QuantityArray]] = None
878
+ """ Average column density of electrons """
879
+ PRESSURE: Optional[Data[tuple[StationId, Time], QuantityArray]] = None
880
+ """ Ambient atmospheric pressure """
881
+ REL_HUMIDITY: Optional[Data[tuple[StationId, Time], QuantityArray]] = None
882
+ """ Ambient relative humidity """
883
+ TEMPERATURE: Optional[Data[tuple[StationId, Time], QuantityArray]] = None
884
+ """ Ambient air temperature for an antenna """
885
+ DEW_POINT: Optional[Data[tuple[StationId, Time], QuantityArray]] = None
886
+ """ Dew point """
887
+ WIND_DIRECTION: Optional[Data[tuple[StationId, Time], QuantityArray]] = None
888
+ """ Average wind direction """
889
+ WIND_SPEED: Optional[Data[tuple[StationId, Time], QuantityArray]] = None
890
+ """ Average wind speed """
891
+ STATION_POSITION: Optional[Data[tuple[StationId], QuantityArray]] = None
892
+ """ Station position """
893
+
894
+ # Attributes
895
+ type: Attr[str] = "weather"
896
+ """
897
+ Type of dataset.
898
+ """
766
899
 
767
900
 
768
901
  @xarray_dataset_schema
@@ -772,9 +905,9 @@ class PointingXds:
772
905
  Mid-point of the time interval for which the information in this row is
773
906
  valid. Required to use the same time measure reference as in visibility dataset
774
907
  """
775
- antenna_id: Coord[AntennaId, Union[int, numpy.int32]]
908
+ antenna_name: Coordof[AntennaNameArray]
776
909
  """
777
- Antenna identifier, as specified by baseline_antenna1/2_id in visibility dataset
910
+ Antenna name, as specified by baseline_antenna1/2_name in visibility dataset
778
911
  """
779
912
  sky_dir_label: Coord[SkyDirLabel, str]
780
913
  """
@@ -782,18 +915,18 @@ class PointingXds:
782
915
  """
783
916
 
784
917
  BEAM_POINTING: Data[
785
- Union[tuple[Time, AntennaId, TimePolynomial], tuple[Time, AntennaId]],
918
+ Union[tuple[Time, AntennaName, TimePolynomial], tuple[Time, AntennaName]],
786
919
  SkyCoordArray,
787
920
  ]
788
921
  """
789
922
  Antenna pointing direction, optionally expressed as polynomial coefficients. DIRECTION in MSv3.
790
923
  """
791
- DISH_MEASURED_POINTING: Optional[Data[tuple[Time, AntennaId], SkyCoordArray]]
924
+ DISH_MEASURED_POINTING: Optional[Data[tuple[Time, AntennaName], SkyCoordArray]]
792
925
  """
793
926
  The current encoder values on the primary axes of the mount type for
794
927
  the antenna. ENCODER in MSv3.
795
928
  """
796
- OVER_THE_TOP: Optional[Data[tuple[Time, AntennaId], bool]]
929
+ OVER_THE_TOP: Optional[Data[tuple[Time, AntennaName], bool]]
797
930
 
798
931
 
799
932
  @xarray_dataset_schema
@@ -810,15 +943,53 @@ class PhasedArrayXds:
810
943
 
811
944
  @xarray_dataset_schema
812
945
  class SystemCalibrationXds:
813
- """TODO: largely incomplete"""
946
+ """System calibration. Contains time- and frequency- variable
947
+ calibration measurements for each antenna, as indexed on receptor"""
814
948
 
815
- antenna_id: Coord[AntennaId, Union[int, numpy.int32]]
949
+ # Coordinates
950
+ antenna_name: Coordof[AntennaNameArray]
816
951
  """ Antenna identifier """
817
- time: Coord[Time, numpy.float64]
952
+ time: Coordof[TimeCoordArray]
818
953
  """ Midpoint of time for which this set of parameters is accurate """
819
- receptor_id: Coord[ReceptorId, numpy.float64]
954
+ receptor_id: Optional[Coord[ReceptorId, numpy.float64]] = None
955
+ """ """
956
+ frequency: Optional[Coordof[FrequencyArray]] = None
820
957
  """ """
821
958
 
959
+ # Data variables (all optional)
960
+ PHASE_DIFFERENCE: Optional[Data[tuple[Time, AntennaName], numpy.float64]] = None
961
+ """ Phase difference between receptor 0 and receptor 1 """
962
+ TCAL: Optional[
963
+ Data[tuple[Time, AntennaName, ReceptorId, Frequency], QuantityArray]
964
+ ] = None
965
+ """ Calibration temp """
966
+ TRX: Optional[
967
+ Data[tuple[Time, AntennaName, ReceptorId, Frequency], QuantityArray]
968
+ ] = None
969
+ """ Receiver temperature """
970
+ TSKY: Optional[
971
+ Data[tuple[Time, AntennaName, ReceptorId, Frequency], QuantityArray]
972
+ ] = None
973
+ """ Sky temperature """
974
+ TSYS: Optional[
975
+ Data[tuple[Time, AntennaName, ReceptorId, Frequency], QuantityArray]
976
+ ] = None
977
+ """ System temperature """
978
+ TANT: Optional[
979
+ Data[tuple[Time, AntennaName, ReceptorId, Frequency], QuantityArray]
980
+ ] = None
981
+ """ Antenna temperature """
982
+ TANT_SYS: Optional[
983
+ Data[tuple[Time, AntennaName, ReceptorId, Frequency], QuantityArray]
984
+ ] = None
985
+ """ TANT/TSYS """
986
+
987
+ # Attributes
988
+ type: Attr[str] = "system_calibration"
989
+ """
990
+ Type of dataset.
991
+ """
992
+
822
993
 
823
994
  @xarray_dataset_schema
824
995
  class VisibilityXds:
@@ -830,7 +1001,12 @@ class VisibilityXds:
830
1001
  The time coordinate is the mid-point of the nominal sampling interval, as
831
1002
  specified in the ``ms_v4.time.attrs['integration_time']`` (ms v2 interval).
832
1003
  """
833
- baseline_id: Coordof[BaselineArray]
1004
+ baseline_id: Optional[Coordof[BaselineArray]] # IF. not present in main_sd_xds
1005
+ """ Baseline ID """
1006
+ antenna_name: Optional[
1007
+ Coordof[AntennaNameArray]
1008
+ ] # Single-dish. not present in main_xds
1009
+ """ antenna_name """
834
1010
  frequency: Coordof[FrequencyArray]
835
1011
  """Center frequencies for each channel."""
836
1012
  polarization: Coordof[PolarizationArray]
@@ -838,18 +1014,18 @@ class VisibilityXds:
838
1014
  Labels for polarization types, e.g. ``['XX','XY','YX','YY']``, ``['RR','RL','LR','LL']``.
839
1015
  """
840
1016
  uvw_label: Optional[Coordof[UvwLabelArray]]
1017
+ """ u,v,w """
1018
+ baseline_antenna1_name: Optional[Coordof[BaselineAntennaNameArray]] # IF
1019
+ """Antenna name for 1st antenna in baseline. Maps to ``attrs['antenna_xds'].antenna_name``"""
1020
+ baseline_antenna2_name: Optional[Coordof[BaselineAntennaNameArray]] # IF
1021
+ """Antenna name for 2nd antenna in baseline. Maps to ``attrs['antenna_xds'].antenna_name``"""
841
1022
 
842
1023
  # --- Required Attributes ---
843
- # TODO: on hold while antenna_xds is reviewed/ updated
844
- # antenna_xds: Attr[AntennaXds]
845
- # antenna_xds: Attr[AntennaXdsEmptyWhileRevampedTODO]
1024
+ partition_info: Attr[PartitionInfoDict]
1025
+ antenna_xds: Attr[AntennaXds]
846
1026
 
847
1027
  # --- Optional Coordinates ---
848
- baseline_antenna1_id: Optional[Coordof[BaselineAntennaArray]] = None
849
- """Antenna id for 1st antenna in baseline. Maps to ``attrs['antenna_xds'].antenna_id``"""
850
- baseline_antenna2_id: Optional[Coordof[BaselineAntennaArray]] = None
851
- """Antenna id for 2nd antenna in baseline. Maps to ``attrs['antenna_xds'].antenna_id``"""
852
- scan_id: Optional[Coord[Time, int]] = None
1028
+ scan_number: Optional[Coord[Time, Union[numpy.int64, numpy.int32]]] = None
853
1029
  """Arbitary scan number to identify data taken in the same logical scan."""
854
1030
 
855
1031
  # --- Required data variables ---
@@ -875,6 +1051,9 @@ class VisibilityXds:
875
1051
  tuple[Time, BaselineId],
876
1052
  tuple[Time, BaselineId, Frequency],
877
1053
  tuple[Time, BaselineId, Frequency, Polarization],
1054
+ tuple[Time, AntennaName], # SD
1055
+ tuple[Time, AntennaName, Frequency], # SD
1056
+ tuple[Time, AntennaName, Frequency, Polarization], # SD
878
1057
  ],
879
1058
  QuantityArray,
880
1059
  ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: xradio
3
- Version: 0.0.36
3
+ Version: 0.0.37
4
4
  Summary: Xarray Radio Astronomy Data IO
5
5
  Author-email: Jan-Willem Steeb <jsteeb@nrao.edu>
6
6
  License: BSD 3-Clause License
File without changes
File without changes
File without changes
File without changes
File without changes