xradio 0.0.39__py3-none-any.whl → 0.0.41__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. xradio/__init__.py +1 -1
  2. xradio/_utils/schema.py +14 -3
  3. xradio/{vis → correlated_data}/__init__.py +3 -2
  4. xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/_tables/load_main_table.py +2 -2
  5. xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/_tables/read.py +15 -1
  6. xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/_tables/read_main_table.py +1 -1
  7. xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/_tables/read_subtables.py +1 -1
  8. xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/_tables/write.py +1 -1
  9. xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/conversion.py +117 -58
  10. xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/create_antenna_xds.py +196 -168
  11. xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/create_field_and_source_xds.py +234 -200
  12. xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/msv2_to_msv4_meta.py +1 -1
  13. xradio/correlated_data/_utils/_ms/msv4_info_dicts.py +203 -0
  14. xradio/correlated_data/_utils/_ms/msv4_sub_xdss.py +516 -0
  15. xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/partition_queries.py +1 -1
  16. xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/partitions.py +1 -1
  17. xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/subtables.py +2 -2
  18. xradio/{vis/_vis_utils → correlated_data/_utils}/_utils/xds_helper.py +1 -1
  19. xradio/{vis/_vis_utils → correlated_data/_utils}/_zarr/read.py +1 -1
  20. xradio/{vis/_vis_utils → correlated_data/_utils}/_zarr/write.py +1 -1
  21. xradio/{vis/_vis_utils → correlated_data/_utils}/ms.py +1 -1
  22. xradio/{vis/_vis_utils → correlated_data/_utils}/zarr.py +4 -4
  23. xradio/{vis → correlated_data}/convert_msv2_to_processing_set.py +10 -3
  24. xradio/correlated_data/correlated_xds.py +13 -0
  25. xradio/{vis → correlated_data}/load_processing_set.py +13 -17
  26. xradio/{vis/read_processing_set.py → correlated_data/open_processing_set.py} +21 -23
  27. xradio/{vis/_processing_set.py → correlated_data/processing_set.py} +11 -12
  28. xradio/{vis → correlated_data}/schema.py +572 -186
  29. xradio/correlated_data/test__processing_set.py +74 -0
  30. xradio/image/_util/_casacore/xds_from_casacore.py +1 -1
  31. xradio/image/_util/_zarr/xds_from_zarr.py +1 -1
  32. xradio/image/_util/_zarr/zarr_low_level.py +1 -1
  33. {xradio-0.0.39.dist-info → xradio-0.0.41.dist-info}/METADATA +10 -10
  34. xradio-0.0.41.dist-info/RECORD +75 -0
  35. {xradio-0.0.39.dist-info → xradio-0.0.41.dist-info}/WHEEL +1 -1
  36. xradio/vis/_vis_utils/_ms/msv4_infos.py +0 -0
  37. xradio/vis/_vis_utils/_ms/msv4_sub_xdss.py +0 -351
  38. xradio-0.0.39.dist-info/RECORD +0 -73
  39. /xradio/{vis/_vis_utils → correlated_data/_utils}/__init__.py +0 -0
  40. /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/_tables/load.py +0 -0
  41. /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/_tables/table_query.py +0 -0
  42. /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/_tables/write_exp_api.py +0 -0
  43. /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/chunks.py +0 -0
  44. /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/descr.py +0 -0
  45. /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/msv2_msv3.py +0 -0
  46. /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/optimised_functions.py +0 -0
  47. /xradio/{vis/_vis_utils → correlated_data/_utils}/_utils/cds.py +0 -0
  48. /xradio/{vis/_vis_utils → correlated_data/_utils}/_utils/partition_attrs.py +0 -0
  49. /xradio/{vis/_vis_utils → correlated_data/_utils}/_utils/stokes_types.py +0 -0
  50. /xradio/{vis/_vis_utils → correlated_data/_utils}/_zarr/encoding.py +0 -0
  51. {xradio-0.0.39.dist-info → xradio-0.0.41.dist-info}/LICENSE.txt +0 -0
  52. {xradio-0.0.39.dist-info → xradio-0.0.41.dist-info}/top_level.txt +0 -0
xradio/__init__.py CHANGED
@@ -1,5 +1,5 @@
1
1
  import os
2
- from graphviper.utils.logger import setup_logger
2
+ from toolviper.utils.logger import setup_logger
3
3
 
4
4
  # _logger_name = "xradio"
5
5
  # if os.getenv("VIPER_LOGGER_NAME") != _logger_name:
xradio/_utils/schema.py CHANGED
@@ -1,12 +1,12 @@
1
- import graphviper.utils.logger as logger
1
+ import toolviper.utils.logger as logger
2
2
  import xarray as xr
3
3
 
4
4
 
5
5
  def convert_generic_xds_to_xradio_schema(
6
6
  generic_xds: xr.Dataset,
7
7
  msv4_xds: xr.Dataset,
8
- to_new_data_variables: dict,
9
- to_new_coords: dict,
8
+ to_new_data_variables: dict[str, list],
9
+ to_new_coords: dict[str, list],
10
10
  ) -> xr.Dataset:
11
11
  """Converts a generic xarray Dataset to the xradio schema.
12
12
 
@@ -55,6 +55,7 @@ def convert_generic_xds_to_xradio_schema(
55
55
  "column_descriptions"
56
56
  ]
57
57
  coords = {}
58
+ coord_attrs = {}
58
59
 
59
60
  name_keys = list(generic_xds.data_vars.keys()) + list(generic_xds.coords.keys())
60
61
 
@@ -80,7 +81,14 @@ def convert_generic_xds_to_xradio_schema(
80
81
  new_coord[1],
81
82
  generic_xds[key].data,
82
83
  )
84
+
85
+ if msv4_measure:
86
+ coord_attrs[new_coord[0]] = msv4_measure
87
+
83
88
  msv4_xds = msv4_xds.assign_coords(coords)
89
+ for coord, coord_attrs in coord_attrs.items():
90
+ msv4_xds.coords[coord].attrs.update(coord_attrs)
91
+
84
92
  return msv4_xds
85
93
 
86
94
 
@@ -102,6 +110,9 @@ def column_description_casacore_to_msv4_measure(
102
110
  casacore_column_description["keywords"]["QuantumUnits"]
103
111
  )
104
112
 
113
+ # Beware: casa_ref won't be found in cases such as the custom
114
+ # 'NRAO_GBT_USER/NRAO_GBT_USER_DIR_REF' in POINTING
115
+ casa_ref = None
105
116
  # Reference frame to convert?
106
117
  if "Ref" in msv4_measure_conversion:
107
118
  # Find reference frame
@@ -1,11 +1,12 @@
1
- from .read_processing_set import read_processing_set
1
+ from .processing_set import ProcessingSet
2
+ from .open_processing_set import open_processing_set
2
3
  from .load_processing_set import load_processing_set
3
4
  from .convert_msv2_to_processing_set import convert_msv2_to_processing_set
4
5
 
5
6
  from .schema import VisibilityXds
6
7
 
7
8
  __all__ = [
8
- "read_processing_set",
9
+ "open_processing_set",
9
10
  "load_processing_set",
10
11
  "convert_msv2_to_processing_set",
11
12
  "VisibilityXds",
@@ -1,4 +1,4 @@
1
- import graphviper.utils.logger as logger
1
+ import toolviper.utils.logger as logger
2
2
  from typing import Dict, List, Tuple, Union
3
3
 
4
4
  import pandas as pd
@@ -12,7 +12,7 @@ from .read_main_table import get_partition_ids, redim_id_data_vars, rename_vars
12
12
  from .read import add_units_measures, convert_casacore_time, extract_table_attributes
13
13
  from .write import revert_time
14
14
  from .table_query import open_query, open_table_ro
15
- from xradio.vis._vis_utils._ms._tables.read_main_table import (
15
+ from xradio.correlated_data._utils._ms._tables.read_main_table import (
16
16
  get_baselines,
17
17
  get_baseline_indices,
18
18
  )
@@ -1,4 +1,4 @@
1
- import graphviper.utils.logger as logger
1
+ import toolviper.utils.logger as logger
2
2
  import os
3
3
  from pathlib import Path
4
4
  import re
@@ -20,9 +20,23 @@ MJD_DIF_UNIX = 40587
20
20
 
21
21
 
22
22
  def table_exists(path: str) -> bool:
23
+ """
24
+ Whether a casacore table exists on disk (in the casacore.tables.tableexists sense)
25
+ """
23
26
  return tables.tableexists(path)
24
27
 
25
28
 
29
+ def table_has_column(path: str, column_name: str) -> bool:
30
+ """
31
+ Whether a column is present in a casacore table
32
+ """
33
+ with open_table_ro(path) as tb_tool:
34
+ if column_name in tb_tool.colnames():
35
+ return True
36
+ else:
37
+ return False
38
+
39
+
26
40
  def convert_casacore_time(
27
41
  rawtimes: np.ndarray, convert_to_datetime: bool = True
28
42
  ) -> np.ndarray:
@@ -1,4 +1,4 @@
1
- import graphviper.utils.logger as logger
1
+ import toolviper.utils.logger as logger
2
2
  from typing import Any, Dict, List, Tuple, Union
3
3
 
4
4
  import dask, dask.array
@@ -1,4 +1,4 @@
1
- import graphviper.utils.logger as logger
1
+ import toolviper.utils.logger as logger
2
2
  from pathlib import Path
3
3
  from typing import Dict, Tuple, Union
4
4
 
@@ -1,4 +1,4 @@
1
- import graphviper.utils.logger as logger, os
1
+ import toolviper.utils.logger as logger, os
2
2
  from typing import Tuple
3
3
 
4
4
  import numpy as np
@@ -1,21 +1,28 @@
1
+ import datetime
2
+ import importlib
1
3
  import numcodecs
2
- import time
3
- from .._zarr.encoding import add_encoding
4
- from typing import Dict, Union
5
- import graphviper.utils.logger as logger
6
4
  import os
7
5
  import pathlib
6
+ import time
7
+ from typing import Dict, Union
8
8
 
9
9
  import numpy as np
10
10
  import xarray as xr
11
11
 
12
+ import toolviper.utils.logger as logger
12
13
  from casacore import tables
13
- from xradio.vis._vis_utils._ms.msv4_sub_xdss import (
14
+ from xradio.correlated_data._utils._ms.msv4_sub_xdss import (
14
15
  create_pointing_xds,
16
+ create_system_calibration_xds,
15
17
  create_weather_xds,
16
18
  )
17
- from xradio.vis._vis_utils._ms.create_antenna_xds import create_antenna_xds
18
- from xradio.vis._vis_utils._ms.create_field_and_source_xds import (
19
+ from .msv4_info_dicts import create_info_dicts
20
+ from xradio.correlated_data._utils._ms.create_antenna_xds import (
21
+ create_antenna_xds,
22
+ create_gain_curve_xds,
23
+ create_phase_calibration_xds,
24
+ )
25
+ from xradio.correlated_data._utils._ms.create_field_and_source_xds import (
19
26
  create_field_and_source_xds,
20
27
  )
21
28
  from xradio._utils.schema import column_description_casacore_to_msv4_measure
@@ -25,6 +32,7 @@ from .msv2_to_msv4_meta import (
25
32
  col_dims,
26
33
  )
27
34
 
35
+ from .._zarr.encoding import add_encoding
28
36
  from .subtables import subt_rename_ids
29
37
  from ._tables.table_query import open_table_ro, open_query
30
38
  from ._tables.read import (
@@ -142,7 +150,7 @@ def mem_chunksize_to_dict_main(chunksize: float, xds: xr.Dataset) -> Dict[str, i
142
150
  polarization).
143
151
  """
144
152
 
145
- sizeof_vis = itemsize_vis_spec(xds)
153
+ sizeof_vis = itemsize_spec(xds)
146
154
  size_all_pols = sizeof_vis * xds.sizes["polarization"]
147
155
  if size_all_pols / GiBYTES_TO_BYTES > chunksize:
148
156
  raise RuntimeError(
@@ -324,7 +332,7 @@ def find_baseline_or_antenna_var(xds: xr.Dataset) -> str:
324
332
  return baseline_or_antenna_name
325
333
 
326
334
 
327
- def itemsize_vis_spec(xds: xr.Dataset) -> int:
335
+ def itemsize_spec(xds: xr.Dataset) -> int:
328
336
  """
329
337
  Size in bytes of one visibility (or spectrum) value.
330
338
  """
@@ -693,6 +701,7 @@ def convert_and_write_partition(
693
701
  pointing_interpolate: bool = False,
694
702
  ephemeris_interpolate: bool = False,
695
703
  phase_cal_interpolate: bool = False,
704
+ sys_cal_interpolate: bool = False,
696
705
  compressor: numcodecs.abc.Codec = numcodecs.Zstd(level=2),
697
706
  storage_backend="zarr",
698
707
  overwrite: bool = False,
@@ -705,7 +714,7 @@ def convert_and_write_partition(
705
714
  _description_
706
715
  out_file : str
707
716
  _description_
708
- obs_mode : str
717
+ intents : str
709
718
  _description_
710
719
  ddi : int, optional
711
720
  _description_, by default 0
@@ -723,6 +732,10 @@ def convert_and_write_partition(
723
732
  _description_, by default None
724
733
  ephemeris_interpolate : bool, optional
725
734
  _description_, by default None
735
+ phase_cal_interpolate : bool, optional
736
+ _description_, by default None
737
+ sys_cal_interpolate : bool, optional
738
+ _description_, by default None
726
739
  compressor : numcodecs.abc.Codec, optional
727
740
  _description_, by default numcodecs.Zstd(level=2)
728
741
  storage_backend : str, optional
@@ -738,7 +751,7 @@ def convert_and_write_partition(
738
751
 
739
752
  taql_where = create_taql_query(partition_info)
740
753
  ddi = partition_info["DATA_DESC_ID"][0]
741
- obs_mode = str(partition_info["OBS_MODE"][0])
754
+ intents = str(partition_info["OBS_MODE"][0])
742
755
 
743
756
  start = time.time()
744
757
  with open_table_ro(in_file) as mtable:
@@ -766,24 +779,32 @@ def convert_and_write_partition(
766
779
  tb_tool.getcol("OBSERVATION_ID"), "OBSERVATION_ID"
767
780
  )
768
781
 
769
- def get_observation_info(in_file, observation_id, obs_mode):
782
+ def get_observation_info(in_file, observation_id, intents):
770
783
  generic_observation_xds = load_generic_table(
771
784
  in_file,
772
785
  "OBSERVATION",
773
786
  taql_where=f" where (ROWID() IN [{str(observation_id)}])",
774
787
  )
775
788
 
776
- if obs_mode == "None":
777
- obs_mode = "obs_" + str(observation_id)
789
+ if intents == "None":
790
+ intents = "obs_" + str(observation_id)
778
791
 
779
- return generic_observation_xds["TELESCOPE_NAME"].values[0], obs_mode
792
+ return generic_observation_xds["TELESCOPE_NAME"].values[0], intents
780
793
 
781
- telescope_name, obs_mode = get_observation_info(
782
- in_file, observation_id, obs_mode
794
+ telescope_name, intents = get_observation_info(
795
+ in_file, observation_id, intents
783
796
  )
784
797
 
785
798
  start = time.time()
786
- xds = xr.Dataset()
799
+ xds = xr.Dataset(
800
+ attrs={
801
+ "creation_date": datetime.datetime.now().isoformat(),
802
+ "xradio_version": importlib.metadata.version("xradio"),
803
+ "schema_version": "4.0.-9999",
804
+ "type": "visibility",
805
+ }
806
+ )
807
+
787
808
  # interval = check_if_consistent(tb_tool.getcol("INTERVAL"), "INTERVAL")
788
809
  interval = tb_tool.getcol("INTERVAL")
789
810
 
@@ -874,22 +895,51 @@ def convert_and_write_partition(
874
895
  antenna_id,
875
896
  feed_id,
876
897
  telescope_name,
898
+ )
899
+
900
+ logger.debug("Time antenna xds " + str(time.time() - start))
901
+
902
+ start = time.time()
903
+ gain_curve_xds = create_gain_curve_xds(
904
+ in_file, xds.frequency.attrs["spectral_window_id"], ant_xds
905
+ )
906
+ logger.debug("Time gain_curve xds " + str(time.time() - start))
907
+
908
+ start = time.time()
909
+ phase_calibration_xds = create_phase_calibration_xds(
910
+ in_file,
911
+ xds.frequency.attrs["spectral_window_id"],
912
+ ant_xds,
877
913
  time_min_max,
878
914
  phase_cal_interp_time,
879
915
  )
916
+ logger.debug("Time phase_calibration xds " + str(time.time() - start))
880
917
 
881
918
  # Change antenna_ids to antenna_names
882
919
  xds = antenna_ids_to_names(xds, ant_xds, is_single_dish)
920
+ # but before, keep the name-id arrays, we need them for the pointing and weather xds
883
921
  ant_xds_name_ids = ant_xds["antenna_name"].set_xindex("antenna_id")
884
- ant_xds = ant_xds.drop_vars(
885
- "antenna_id"
886
- ) # No longer needed after converting to name.
922
+ ant_xds_station_name_ids = ant_xds["station"].set_xindex("antenna_id")
923
+ # No longer needed after converting to name.
924
+ ant_xds = ant_xds.drop_vars("antenna_id")
887
925
 
888
- logger.debug("Time ant xds " + str(time.time() - start))
926
+ # Create system_calibration_xds
927
+ start = time.time()
928
+ if sys_cal_interpolate:
929
+ sys_cal_interp_time = xds.time.values
930
+ else:
931
+ sys_cal_interp_time = None
932
+ system_calibration_xds = create_system_calibration_xds(
933
+ in_file,
934
+ xds.frequency,
935
+ ant_xds_name_ids,
936
+ sys_cal_interp_time,
937
+ )
938
+ logger.debug("Time system_calibation " + str(time.time() - start))
889
939
 
890
940
  # Create weather_xds
891
941
  start = time.time()
892
- weather_xds = create_weather_xds(in_file)
942
+ weather_xds = create_weather_xds(in_file, ant_xds_station_name_ids)
893
943
  logger.debug("Time weather " + str(time.time() - start))
894
944
 
895
945
  # Create pointing_xds
@@ -914,7 +964,6 @@ def convert_and_write_partition(
914
964
  )
915
965
 
916
966
  start = time.time()
917
- xds.attrs["type"] = "visibility"
918
967
 
919
968
  # Time and frequency should always be increasing
920
969
  if len(xds.frequency) > 1 and xds.frequency[1] - xds.frequency[0] < 0:
@@ -943,7 +992,7 @@ def convert_and_write_partition(
943
992
  # assert len(col_unique) == 1, col_name + " is not consistent."
944
993
  # return col_unique[0]
945
994
 
946
- field_and_source_xds, source_id, num_lines = create_field_and_source_xds(
995
+ field_and_source_xds, source_id, _num_lines = create_field_and_source_xds(
947
996
  in_file,
948
997
  field_id,
949
998
  xds.frequency.attrs["spectral_window_id"],
@@ -965,11 +1014,18 @@ def convert_and_write_partition(
965
1014
  "FIELD_PHASE_CENTER"
966
1015
  ].attrs["frame"]
967
1016
 
968
- if overwrite:
969
- mode = "w"
970
- else:
971
- mode = "w-"
1017
+ partition_info_misc_fields = {
1018
+ "scan_id": scan_id,
1019
+ "intents": intents,
1020
+ "taql_where": taql_where,
1021
+ }
1022
+ info_dicts = create_info_dicts(
1023
+ in_file, xds, field_and_source_xds, partition_info_misc_fields, tb_tool
1024
+ )
1025
+ xds.attrs.update(info_dicts)
972
1026
 
1027
+ # xds ready, prepare to write
1028
+ start = time.time()
973
1029
  main_chunksize = parse_chunksize(main_chunksize, "main", xds)
974
1030
  add_encoding(xds, compressor=compressor, chunks=main_chunksize)
975
1031
  logger.debug("Time add compressor and chunk " + str(time.time() - start))
@@ -979,31 +1035,10 @@ def convert_and_write_partition(
979
1035
  pathlib.Path(in_file).name.replace(".ms", "") + "_" + str(ms_v4_id),
980
1036
  )
981
1037
 
982
- if "line_name" in field_and_source_xds.coords:
983
- line_name = to_list(
984
- unique_1d(np.ravel(field_and_source_xds.line_name.values))
985
- )
1038
+ if overwrite:
1039
+ mode = "w"
986
1040
  else:
987
- line_name = []
988
-
989
- xds.attrs["partition_info"] = {
990
- # "spectral_window_id": xds.frequency.attrs["spectral_window_id"],
991
- "spectral_window_name": xds.frequency.attrs["spectral_window_name"],
992
- # "field_id": to_list(unique_1d(field_id)),
993
- "field_name": to_list(
994
- np.unique(field_and_source_xds.field_name.values)
995
- ),
996
- # "source_id": to_list(unique_1d(source_id)),
997
- "line_name": line_name,
998
- "scan_number": to_list(np.unique(scan_id)),
999
- "source_name": to_list(
1000
- np.unique(field_and_source_xds.source_name.values)
1001
- ),
1002
- "polarization_setup": to_list(xds.polarization.values),
1003
- "num_lines": num_lines,
1004
- "obs_mode": obs_mode.split(","),
1005
- "taql": taql_where,
1006
- }
1041
+ mode = "w-"
1007
1042
 
1008
1043
  start = time.time()
1009
1044
  if storage_backend == "zarr":
@@ -1022,6 +1057,21 @@ def convert_and_write_partition(
1022
1057
  store=os.path.join(file_name, "POINTING"), mode=mode
1023
1058
  )
1024
1059
 
1060
+ if system_calibration_xds:
1061
+ system_calibration_xds.to_zarr(
1062
+ store=os.path.join(file_name, "SYSCAL"), mode=mode
1063
+ )
1064
+
1065
+ if gain_curve_xds:
1066
+ gain_curve_xds.to_zarr(
1067
+ store=os.path.join(file_name, "GAIN_CURVE"), mode=mode
1068
+ )
1069
+
1070
+ if phase_calibration_xds:
1071
+ phase_calibration_xds.to_zarr(
1072
+ store=os.path.join(file_name, "PHASE_CAL"), mode=mode
1073
+ )
1074
+
1025
1075
  if weather_xds:
1026
1076
  weather_xds.to_zarr(
1027
1077
  store=os.path.join(file_name, "WEATHER"), mode=mode
@@ -1080,7 +1130,7 @@ def add_data_groups(xds):
1080
1130
  xds.attrs["data_groups"] = {}
1081
1131
  if "VISIBILITY" in xds:
1082
1132
  xds.attrs["data_groups"]["base"] = {
1083
- "visibility": "VISIBILITY",
1133
+ "correlated_data": "VISIBILITY",
1084
1134
  "flag": "FLAG",
1085
1135
  "weight": "WEIGHT",
1086
1136
  "uvw": "UVW",
@@ -1088,7 +1138,7 @@ def add_data_groups(xds):
1088
1138
 
1089
1139
  if "VISIBILITY_CORRECTED" in xds:
1090
1140
  xds.attrs["data_groups"]["corrected"] = {
1091
- "visibility": "VISIBILITY_CORRECTED",
1141
+ "correlated_data": "VISIBILITY_CORRECTED",
1092
1142
  "flag": "FLAG",
1093
1143
  "weight": "WEIGHT",
1094
1144
  "uvw": "UVW",
@@ -1096,7 +1146,7 @@ def add_data_groups(xds):
1096
1146
 
1097
1147
  if "VISIBILITY_MODEL" in xds:
1098
1148
  xds.attrs["data_groups"]["model"] = {
1099
- "visibility": "VISIBILITY_MODEL",
1149
+ "correlated_data": "VISIBILITY_MODEL",
1100
1150
  "flag": "FLAG",
1101
1151
  "weight": "WEIGHT",
1102
1152
  "uvw": "UVW",
@@ -1105,7 +1155,16 @@ def add_data_groups(xds):
1105
1155
  is_single_dish = False
1106
1156
  if "SPECTRUM" in xds:
1107
1157
  xds.attrs["data_groups"]["base"] = {
1108
- "spectrum": "SPECTRUM",
1158
+ "correlated_data": "SPECTRUM",
1159
+ "flag": "FLAG",
1160
+ "weight": "WEIGHT",
1161
+ "uvw": "UVW",
1162
+ }
1163
+ is_single_dish = True
1164
+
1165
+ if "SPECTRUM_MODEL" in xds:
1166
+ xds.attrs["data_groups"]["model"] = {
1167
+ "correlated_data": "SPECTRUM_MODEL",
1109
1168
  "flag": "FLAG",
1110
1169
  "weight": "WEIGHT",
1111
1170
  "uvw": "UVW",
@@ -1114,7 +1173,7 @@ def add_data_groups(xds):
1114
1173
 
1115
1174
  if "SPECTRUM_CORRECTED" in xds:
1116
1175
  xds.attrs["data_groups"]["corrected"] = {
1117
- "spectrum": "SPECTRUM_CORRECTED",
1176
+ "correlated_data": "SPECTRUM_CORRECTED",
1118
1177
  "flag": "FLAG",
1119
1178
  "weight": "WEIGHT",
1120
1179
  "uvw": "UVW",