xradio 0.0.41__py3-none-any.whl → 0.0.43__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 (62) hide show
  1. xradio/_utils/coord_math.py +100 -0
  2. xradio/_utils/list_and_array.py +49 -4
  3. xradio/_utils/schema.py +36 -16
  4. xradio/image/_util/_casacore/xds_from_casacore.py +5 -5
  5. xradio/image/_util/_casacore/xds_to_casacore.py +12 -11
  6. xradio/image/_util/_fits/xds_from_fits.py +18 -17
  7. xradio/image/_util/_zarr/zarr_low_level.py +29 -12
  8. xradio/image/_util/common.py +1 -1
  9. xradio/image/_util/image_factory.py +1 -1
  10. xradio/{correlated_data → measurement_set}/__init__.py +7 -4
  11. xradio/measurement_set/_utils/__init__.py +5 -0
  12. xradio/{correlated_data/_utils/_ms → measurement_set/_utils/_msv2}/_tables/load_main_table.py +1 -1
  13. xradio/{correlated_data/_utils/_ms → measurement_set/_utils/_msv2}/_tables/read.py +1 -1
  14. xradio/{correlated_data/_utils/_ms → measurement_set/_utils/_msv2}/conversion.py +115 -37
  15. xradio/{correlated_data/_utils/_ms → measurement_set/_utils/_msv2}/create_antenna_xds.py +62 -37
  16. xradio/{correlated_data/_utils/_ms → measurement_set/_utils/_msv2}/create_field_and_source_xds.py +117 -25
  17. xradio/{correlated_data/_utils/_ms → measurement_set/_utils/_msv2}/msv4_sub_xdss.py +47 -13
  18. xradio/{correlated_data/_utils/_ms → measurement_set/_utils/_msv2}/partition_queries.py +4 -0
  19. xradio/{correlated_data → measurement_set}/_utils/_utils/xds_helper.py +1 -1
  20. xradio/{correlated_data/_utils/ms.py → measurement_set/_utils/msv2.py} +4 -4
  21. xradio/{correlated_data → measurement_set}/convert_msv2_to_processing_set.py +7 -2
  22. xradio/{correlated_data → measurement_set}/load_processing_set.py +5 -5
  23. xradio/measurement_set/measurement_set_xds.py +110 -0
  24. xradio/{correlated_data → measurement_set}/open_processing_set.py +9 -16
  25. xradio/measurement_set/processing_set.py +777 -0
  26. xradio/{correlated_data → measurement_set}/schema.py +1110 -586
  27. xradio/schema/check.py +42 -22
  28. xradio/schema/dataclass.py +56 -6
  29. xradio/sphinx/__init__.py +12 -0
  30. xradio/sphinx/schema_table.py +351 -0
  31. {xradio-0.0.41.dist-info → xradio-0.0.43.dist-info}/METADATA +9 -6
  32. xradio-0.0.43.dist-info/RECORD +76 -0
  33. {xradio-0.0.41.dist-info → xradio-0.0.43.dist-info}/WHEEL +1 -1
  34. xradio/_utils/common.py +0 -101
  35. xradio/correlated_data/_utils/__init__.py +0 -5
  36. xradio/correlated_data/correlated_xds.py +0 -13
  37. xradio/correlated_data/processing_set.py +0 -301
  38. xradio/correlated_data/test__processing_set.py +0 -74
  39. xradio-0.0.41.dist-info/RECORD +0 -75
  40. /xradio/{correlated_data/_utils/_ms → measurement_set/_utils/_msv2}/_tables/load.py +0 -0
  41. /xradio/{correlated_data/_utils/_ms → measurement_set/_utils/_msv2}/_tables/read_main_table.py +0 -0
  42. /xradio/{correlated_data/_utils/_ms → measurement_set/_utils/_msv2}/_tables/read_subtables.py +0 -0
  43. /xradio/{correlated_data/_utils/_ms → measurement_set/_utils/_msv2}/_tables/table_query.py +0 -0
  44. /xradio/{correlated_data/_utils/_ms → measurement_set/_utils/_msv2}/_tables/write.py +0 -0
  45. /xradio/{correlated_data/_utils/_ms → measurement_set/_utils/_msv2}/_tables/write_exp_api.py +0 -0
  46. /xradio/{correlated_data/_utils/_ms → measurement_set/_utils/_msv2}/chunks.py +0 -0
  47. /xradio/{correlated_data/_utils/_ms → measurement_set/_utils/_msv2}/descr.py +0 -0
  48. /xradio/{correlated_data/_utils/_ms → measurement_set/_utils/_msv2}/msv2_msv3.py +0 -0
  49. /xradio/{correlated_data/_utils/_ms → measurement_set/_utils/_msv2}/msv2_to_msv4_meta.py +0 -0
  50. /xradio/{correlated_data/_utils/_ms → measurement_set/_utils/_msv2}/msv4_info_dicts.py +0 -0
  51. /xradio/{correlated_data/_utils/_ms → measurement_set/_utils/_msv2}/optimised_functions.py +0 -0
  52. /xradio/{correlated_data/_utils/_ms → measurement_set/_utils/_msv2}/partitions.py +0 -0
  53. /xradio/{correlated_data/_utils/_ms → measurement_set/_utils/_msv2}/subtables.py +0 -0
  54. /xradio/{correlated_data → measurement_set}/_utils/_utils/cds.py +0 -0
  55. /xradio/{correlated_data → measurement_set}/_utils/_utils/partition_attrs.py +0 -0
  56. /xradio/{correlated_data → measurement_set}/_utils/_utils/stokes_types.py +0 -0
  57. /xradio/{correlated_data → measurement_set}/_utils/_zarr/encoding.py +0 -0
  58. /xradio/{correlated_data → measurement_set}/_utils/_zarr/read.py +0 -0
  59. /xradio/{correlated_data → measurement_set}/_utils/_zarr/write.py +0 -0
  60. /xradio/{correlated_data → measurement_set}/_utils/zarr.py +0 -0
  61. {xradio-0.0.41.dist-info → xradio-0.0.43.dist-info}/LICENSE.txt +0 -0
  62. {xradio-0.0.41.dist-info → xradio-0.0.43.dist-info}/top_level.txt +0 -0
@@ -12,12 +12,16 @@ import numpy
12
12
  # Dimensions
13
13
  Time = Literal["time"]
14
14
  """ Observation time dimension """
15
- TimePointing = Literal["time_pointing"]
16
- """ time dimension of pointing dataset (when not interpolated to main time) """
15
+ TimeCal = Literal["time_cal"]
16
+ """ time dimension of system calibration (when not interpolated to main time)"""
17
17
  TimeEphemeris = Literal["time_ephemeris"]
18
18
  """ time dimension of ephemeris data (when not interpolated to main time) """
19
- TimeCal = Literal["time_cal"]
20
- """ time dimension of system calibration (when not interpolated to main time) """
19
+ TimePhaseCal = Literal["time_phase_cal"]
20
+ """ Coordinate label for VLBI-specific phase cal time axis """
21
+ TimePointing = Literal["time_pointing"]
22
+ """ time dimension of pointing dataset (when not interpolated to main time) """
23
+ TimeWeather = Literal["time_weather"]
24
+ """ time dimension of weather dataset (when not interpolated to main time) """
21
25
  AntennaName = Literal["antenna_name"]
22
26
  """ Antenna name dimension """
23
27
  StationName = Literal["station_name"]
@@ -50,8 +54,6 @@ EllipsoidPosLabel = Literal["ellipsoid_pos_label"]
50
54
  """ Coordinate labels of geodetic earth location data (typically shape 3 and 'lon', 'lat', 'height')"""
51
55
  CartesianPosLabel = Literal["cartesian_pos_label"]
52
56
  """ Coordinate labels of geocentric earth location data (typically shape 3 and 'x', 'y', 'z')"""
53
- TimePhaseCal = Literal["time_phase_cal"]
54
- """ Coordinate label for VLBI-specific phase cal time axis """
55
57
  nPolynomial = Literal["n_polynomial"]
56
58
  """ For data that is represented as variable in time using Taylor expansion """
57
59
  PolyTerm = Literal["poly_term"]
@@ -63,13 +65,157 @@ LineLabel = Literal["line_label"]
63
65
  # zero dimensions.
64
66
  ZD = tuple[()]
65
67
 
68
+
69
+ # Types of quantity and measures
70
+ Quantity = Literal["quantity"]
71
+ SkyCoord = Literal["sky_coord"]
72
+ SpectralCoord = Literal["spectral_coord"]
73
+ Location = Literal["location"]
74
+ Doppler = Literal["doppler"]
75
+
76
+
77
+ # Units of quantities and measures
78
+ UnitsSeconds = list[Literal["s"]]
79
+ UnitsHertz = list[Literal["Hz"]]
80
+ UnitsMeters = list[Literal["m"]]
81
+
82
+ UnitsOfSkyCoordInRadians = list[Literal["rad"], Literal["rad"]]
83
+ UnitsOfLocationInMetersOrRadians = Union[
84
+ list[Literal["m"], Literal["m"], Literal["m"]],
85
+ list[Literal["rad"], Literal["rad"], Literal["m"]],
86
+ ]
87
+ UnitsOfPositionInRadians = list[Literal["rad"], Literal["rad"], Literal["m"]]
88
+ UnitsOfDopplerShift = Union[list[Literal["ratio"]], list[Literal["m/s"]]]
89
+
90
+ UnitsRadians = list[Literal["rad"]]
91
+ UnitsKelvin = list[Literal["K"]]
92
+ UnitsKelvinPerJansky = list[Literal["K/Jy"]]
93
+ UnitsMetersPerSecond = list[Literal["m/s"]]
94
+ UnitsPascal = list[Literal["Pa"]] # hPa? (in MSv2)
95
+ UnitsPerSquareMeters = list[Literal["/m^2"]]
96
+
97
+
66
98
  # Quantities
67
99
 
68
100
 
101
+ @xarray_dataarray_schema
102
+ class QuantityInSecondsArray:
103
+ """
104
+ Quantity with units of seconds
105
+ """
106
+
107
+ data: Data[ZD, float]
108
+
109
+ units: Attr[UnitsSeconds]
110
+ type: Attr[Quantity] = "quantity"
111
+
112
+
113
+ @xarray_dataarray_schema
114
+ class QuantityInHertzArray:
115
+ """
116
+ Quantity with units of Hertz
117
+ """
118
+
119
+ data: Data[ZD, float]
120
+
121
+ units: Attr[UnitsHertz]
122
+ type: Attr[Quantity] = "quantity"
123
+
124
+
125
+ @xarray_dataarray_schema
126
+ class QuantityInMetersArray:
127
+ """
128
+ Quantity with units of Hertz
129
+ """
130
+
131
+ data: Data[ZD, float]
132
+
133
+ units: Attr[UnitsMeters]
134
+ type: Attr[Quantity] = "quantity"
135
+
136
+
137
+ @xarray_dataarray_schema
138
+ class QuantityInMetersPerSecondArray:
139
+ """
140
+ Quantity with units of Hertz
141
+ """
142
+
143
+ data: Data[ZD, float]
144
+
145
+ units: Attr[UnitsMetersPerSecond]
146
+ type: Attr[Quantity] = "quantity"
147
+
148
+
149
+ @xarray_dataarray_schema
150
+ class QuantityInRadiansArray:
151
+ """
152
+ Quantity with units of Hertz
153
+ """
154
+
155
+ data: Data[ZD, float]
156
+
157
+ units: Attr[UnitsRadians]
158
+ type: Attr[Quantity] = "quantity"
159
+
160
+
161
+ @xarray_dataarray_schema
162
+ class QuantityInKelvinArray:
163
+ """
164
+ Quantity with units of Kelvins
165
+ """
166
+
167
+ data: Data[ZD, float]
168
+
169
+ units: Attr[UnitsKelvin]
170
+ type: Attr[Quantity] = "quantity"
171
+
172
+
173
+ @xarray_dataarray_schema
174
+ class QuantityInKelvinPerJanskyArray:
175
+ """
176
+ Quantity with units of K/Jy (sensitivity in gain curve)
177
+ """
178
+
179
+ data: Data[ZD, numpy.float64]
180
+
181
+ units: Attr[UnitsKelvinPerJansky]
182
+ type: Attr[Quantity] = "quantity"
183
+
184
+
185
+ @xarray_dataarray_schema
186
+ class QuantityInPascalArray:
187
+ """
188
+ Quantity with units of Pa
189
+ """
190
+
191
+ data: Data[ZD, numpy.float64]
192
+
193
+ units: Attr[UnitsPascal]
194
+ type: Attr[Quantity] = "quantity"
195
+
196
+
197
+ @xarray_dataarray_schema
198
+ class QuantityInPerSquareMetersArray:
199
+ """
200
+ Quantity with units of /m^2
201
+ """
202
+
203
+ data: Data[ZD, numpy.float64]
204
+
205
+ units: Attr[UnitsPerSquareMeters]
206
+ type: Attr[Quantity] = "quantity"
207
+
208
+
209
+ AllowedTimeScales = Literal["tai", "tcb", "tcg", "tdb", "tt", "ut1", "utc"]
210
+
211
+
212
+ AllowedTimeFormats = Literal["unix", "mjd", "cxcsec", "gps"]
213
+
214
+
69
215
  @xarray_dataarray_schema
70
216
  class TimeArray:
71
217
  """
72
- Representation of a time quantity.
218
+ Representation of a time measure.
73
219
 
74
220
  :py:class:`astropy.time.Time` serves as the reference implementation.
75
221
  Data can be converted as follows::
@@ -91,26 +237,64 @@ class TimeArray:
91
237
  data: Data[ZD, float]
92
238
  """Time since epoch, typically in seconds (see ``units``)."""
93
239
 
94
- scale: Attr[str] = "tai"
240
+ type: Attr[Time] = "time"
241
+ """ Array type. Should be ``"time"``. """
242
+ units: Attr[UnitsSeconds] = ("s",)
243
+ """ Units to associate with axis"""
244
+ scale: Attr[AllowedTimeScales] = "utc"
95
245
  """
96
246
  Time scale of data. Must be one of ``(‘tai’, ‘tcb’, ‘tcg’, ‘tdb’, ‘tt’, ‘ut1’, ‘utc’)``,
97
247
  see :py:class:`astropy.time.Time`
98
248
  """
99
- format: Attr[str] = "unix_tai"
249
+ format: Attr[AllowedTimeFormats] = "unix"
100
250
  """Time representation and epoch, see :py:class:`TimeArray`."""
101
251
 
102
- type: Attr[str] = "time"
103
- units: Attr[list[str]] = ("s",)
252
+
253
+ # Taken from the list of astropy built-in frame classes: https://docs.astropy.org/en/stable/coordinates/index.html
254
+ AllowedSkyCoordFrames = Literal[
255
+ "icrs",
256
+ "fk5",
257
+ "fk4",
258
+ "fk4noterms",
259
+ "galactic",
260
+ "galactocentric",
261
+ "supergalactic",
262
+ "altaz",
263
+ "hadec",
264
+ "gcrs",
265
+ "cirs",
266
+ "itrs",
267
+ "hcrs",
268
+ "teme",
269
+ "tete",
270
+ "precessedgeocentric",
271
+ "geocentricmeanecliptic",
272
+ "barycentricmeanecliptic",
273
+ "heliocentricmeanecliptic",
274
+ "geocentrictrueecliptic",
275
+ "barycentrictrueecliptic",
276
+ "heliocentrictrueecliptic",
277
+ "heliocentriceclipticiau76",
278
+ "custombarycentricecliptic",
279
+ "lsr",
280
+ "lsrk",
281
+ "lsrd",
282
+ "galacticlsr",
283
+ ]
104
284
 
105
285
 
106
286
  @xarray_dataarray_schema
107
287
  class SkyCoordArray:
288
+ """Measures array for data variables that are sky coordinates, used in :py:class:`FieldSourceXds`"""
289
+
108
290
  data: Data[Union[SkyDirLabel, SkyPosLabel], float]
109
291
 
110
- type: Attr[str] = "sky_coord"
111
- units: Attr[list[str]] = ("rad", "rad")
112
- frame: Attr[str] = ""
292
+ type: Attr[SkyCoord] = "sky_coord"
293
+ units: Attr[UnitsOfSkyCoordInRadians] = ("rad", "rad")
294
+ frame: Attr[AllowedSkyCoordFrames] = ""
113
295
  """
296
+ Possible values are astropy SkyCoord frames.
297
+ Several casacore frames found in MSv2 are translated to astropy frames as follows: AZELGEO=>altaz, J2000=>fk5, ICRS=>icrs.
114
298
  From fixvis docs: clean and the im tool ignore the reference frame
115
299
  claimed by the UVW column (it is often mislabelled as ITRF when it is
116
300
  really FK5 (J2000)) and instead assume the (u, v, w)s are in the same frame
@@ -122,65 +306,61 @@ class SkyCoordArray:
122
306
 
123
307
  @xarray_dataarray_schema
124
308
  class LocalSkyCoordArray:
125
- """Coordinate array for the arrays that have coordinate local_sky_dir_label
126
- in pointing_xds"""
309
+ """Measures array for the arrays that have coordinate local_sky_dir_label in :py:class:`PointingXds`"""
127
310
 
128
311
  data: Data[LocalSkyDirLabel, float]
129
312
 
130
- type: Attr[str] = "sky_coord"
131
- units: Attr[list[str]] = ("rad", "rad")
132
- frame: Attr[str] = ""
313
+ type: Attr[SkyCoord] = "sky_coord"
314
+ units: Attr[UnitsOfSkyCoordInRadians] = ("rad", "rad")
315
+ frame: Attr[AllowedSkyCoordFrames] = "fk5"
133
316
  """
317
+ From fixvis docs: clean and the im tool ignore the reference frame claimed by the UVW column (it is often mislabelled
318
+ 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
319
+ center. calcuvw does not yet force the UVW column and field centers to use the same reference frame! Blank = use the
320
+ phase tracking frame of vis.
134
321
  """
135
322
 
136
323
 
324
+ # Coordinates / Axes
137
325
  @xarray_dataarray_schema
138
- class SkyCoordOffsetArray:
139
- data: Data[Union[SkyDirLabel, SkyPosLabel], float]
140
-
141
- type: Attr[str] = "sky_coord"
142
- units: Attr[list[str]] = ("rad", "rad")
326
+ class TimeCoordArray:
327
+ """Data model of the main dataset time axis. See also :py:class:`TimeArray`."""
143
328
 
144
-
145
- @xarray_dataarray_schema
146
- class QuantityArray:
329
+ data: Data[Time, float]
147
330
  """
148
- Anonymous quantity, possibly with associated units
149
-
150
- Often used for distances / differences (integration time, channel width etcetera).
331
+ Time, expressed in seconds since the epoch (see ``scale`` &
332
+ ``format``), see also see :py:class:`TimeArray`.
151
333
  """
152
334
 
153
- data: Data[ZD, float]
335
+ type: Attr[Time] = "time"
336
+ """ Coordinate type. Should be ``"time"``. """
154
337
 
155
- units: Attr[list[str]]
156
- type: Attr[str] = "quantity"
338
+ units: Attr[UnitsSeconds] = ("s",)
339
+ """ Units to associate with axis"""
157
340
 
341
+ scale: Attr[AllowedTimeScales] = "utc"
342
+ """ Astropy time scales, see :py:class:`TimeArray` """
158
343
 
159
- # Coordinates / Axes
160
- class TimeCoordArrayBase:
161
- """Base class with the metadata found in time array coords."""
344
+ format: Attr[AllowedTimeFormats] = "unix"
345
+ """ Astropy format, see :py:class:`TimeArray`"""
162
346
 
163
- integration_time: Optional[Attr[QuantityArray]] = None
347
+ integration_time: Attr[QuantityInSecondsArray] = None
164
348
  """ The nominal sampling interval (ms v2). Units of seconds. """
165
- effective_integration_time: Optional[Attr[str]] = None
166
- """
167
- Name of data array that contains the integration time that includes
168
- the effects of missing data.
169
- """
170
-
171
- units: Attr[list[str]] = ("s",)
172
- """ Units to associate with axis"""
173
- scale: Attr[str] = "tai"
174
- """ Astropy time scales, see :py:class:`TimeArray` """
175
- format: Attr[str] = "unix"
176
- """ Astropy format, see :py:class:`TimeArray`"""
177
- long_name: Optional[Attr[str]] = "Observation Time"
178
- """ Long-form name to use for axis"""
179
349
 
180
350
 
181
351
  @xarray_dataarray_schema
182
- class TimeCoordArray(TimeCoordArrayBase):
183
- """Data model of visibility time axis. See also :py:class:`TimeArray`."""
352
+ class TimeInterpolatedCoordArray:
353
+ """
354
+ Data model of a time axis when it is interpolated to match the time
355
+ axis of the main dataset. This can be used in the system_calibration_xds,
356
+ pointing_xds, weather_xds, field_and_source_info_xds, and phase_cal_xds
357
+ when their respective time_cal, time_pointing, time_weather,
358
+ time_ephemeris or time_phase_cal are interpolated to the main dataset
359
+ time. See also :py:class:`TimeArray`.
360
+
361
+ The only difference with respect to the main TimeCoordArray is the
362
+ absence of the attribute integration_time
363
+ """
184
364
 
185
365
  data: Data[Time, float]
186
366
  """
@@ -188,14 +368,23 @@ class TimeCoordArray(TimeCoordArrayBase):
188
368
  ``format``), see also see :py:class:`TimeArray`.
189
369
  """
190
370
 
191
- type: Attr[str] = "time"
371
+ type: Attr[Time] = "time"
192
372
  """ Coordinate type. Should be ``"time"``. """
193
373
 
374
+ units: Attr[UnitsSeconds] = ("s",)
375
+ """ Units to associate with axis"""
376
+
377
+ scale: Attr[AllowedTimeScales] = "utc"
378
+ """ Astropy time scales, see :py:class:`TimeArray` """
379
+
380
+ format: Attr[AllowedTimeFormats] = "unix"
381
+ """ Astropy format, see :py:class:`TimeArray`"""
382
+
194
383
 
195
384
  @xarray_dataarray_schema
196
- class TimeCalCoordArray(TimeCoordArrayBase):
385
+ class TimeCalCoordArray:
197
386
  """Data model of 'time_cal' axis (time axis in system_calibration_xds
198
- when not interpolated to the main time axis. See also
387
+ subdataset when not interpolated to the main time axis. See also
199
388
  :py:class:`TimeCoordArray`."""
200
389
 
201
390
  data: Data[TimeCal, float]
@@ -204,14 +393,23 @@ class TimeCalCoordArray(TimeCoordArrayBase):
204
393
  ``format``).
205
394
  """
206
395
 
207
- type: Attr[str] = "time_cal"
396
+ type: Attr[Time] = "time_cal"
208
397
  """ Coordinate type. Should be ``"time_cal"``. """
209
398
 
399
+ units: Attr[UnitsSeconds] = ("s",)
400
+ """ Units to associate with axis"""
401
+
402
+ scale: Attr[AllowedTimeScales] = "utc"
403
+ """ Astropy time scales, see :py:class:`TimeArray` """
404
+
405
+ format: Attr[AllowedTimeFormats] = "unix"
406
+ """ Astropy format, see :py:class:`TimeArray`"""
407
+
210
408
 
211
409
  @xarray_dataarray_schema
212
- class TimePointingCoordArray(TimeCoordArrayBase):
213
- """Data model of 'time_pointing' axis (time axis in pointing_xds
214
- when not interpolated to the main time axis. See also
410
+ class TimePointingCoordArray:
411
+ """Data model of the 'time_pointing' axis (time axis in pointing_xds
412
+ subdataset when not interpolated to the main time axis. See also
215
413
  :py:class:`TimeCoordArray`."""
216
414
 
217
415
  data: Data[TimePointing, float]
@@ -220,15 +418,24 @@ class TimePointingCoordArray(TimeCoordArrayBase):
220
418
  ``format``).
221
419
  """
222
420
 
223
- type: Attr[str] = "time_pointing"
421
+ type: Attr[TimePointing] = "time_pointing"
224
422
  """ Coordinate type. Should be ``"time_pointing"``. """
225
423
 
424
+ units: Attr[UnitsSeconds] = ("s",)
425
+ """ Units to associate with axis"""
426
+
427
+ scale: Attr[AllowedTimeScales] = "utc"
428
+ """ Astropy time scales, see :py:class:`TimeArray` """
429
+
430
+ format: Attr[AllowedTimeFormats] = "unix"
431
+ """ Astropy format, see :py:class:`TimeArray`"""
432
+
226
433
 
227
434
  @xarray_dataarray_schema
228
- class TimeEphemerisCoordArray(TimeCoordArrayBase):
229
- """Data model of 'time_ephemeris' axis (time axis in field_and_source_info_xds
230
- when not interpolated to the main time axis. See also
231
- :py:class:`TimeCoordArray`."""
435
+ class TimeEphemerisCoordArray:
436
+ """Data model of the 'time_ephemeris' axis (time axis in the
437
+ field_and_source_info_xds subdataset when not interpolated to the main
438
+ time axis. See also :py:class:`TimeCoordArray`."""
232
439
 
233
440
  data: Data[TimeEphemeris, float]
234
441
  """
@@ -236,71 +443,129 @@ class TimeEphemerisCoordArray(TimeCoordArrayBase):
236
443
  ``format``).
237
444
  """
238
445
 
239
- type: Attr[str] = "time_ephemeris"
446
+ type: Attr[TimeEphemeris] = "time_ephemeris"
240
447
  """ Coordinate type. Should be ``"time_ephemeris"``. """
241
448
 
449
+ units: Attr[UnitsSeconds] = ("s",)
450
+ """ Units to associate with axis"""
451
+
452
+ scale: Attr[AllowedTimeScales] = "utc"
453
+ """ Astropy time scales, see :py:class:`TimeArray` """
454
+
455
+ format: Attr[AllowedTimeFormats] = "unix"
456
+ """ Astropy format, see :py:class:`TimeArray`"""
457
+
242
458
 
243
459
  @xarray_dataarray_schema
244
- class SpectralCoordArray:
245
- data: Data[ZD, float]
460
+ class TimeWeatherCoordArray:
461
+ """Data model of the 'time_weather' axis (time axis in the weather_xds
462
+ subdataset when not interpolated to the main time axis. See also
463
+ :py:class:`TimeCoordArray`."""
246
464
 
247
- frame: Attr[str] = "gcrs"
248
- """Astropy time scales."""
465
+ data: Data[TimeWeather, float]
466
+ """
467
+ Time, expressed in seconds since the epoch (see ``scale`` &
468
+ ``format``).
469
+ """
249
470
 
250
- type: Attr[str] = "frequency"
251
- units: Attr[list[str]] = ("Hz",)
471
+ type: Attr[Time] = "time_weather"
472
+ """ Coordinate type. Should be ``"time_weather"``. """
252
473
 
474
+ units: Attr[UnitsSeconds] = ("s",)
475
+ """ Units to associate with axis"""
476
+
477
+ scale: Attr[AllowedTimeScales] = "utc"
478
+ """ Astropy time scales, see :py:class:`TimeArray` """
479
+
480
+ format: Attr[AllowedTimeFormats] = "unix"
481
+ """ Astropy format, see :py:class:`TimeArray`"""
253
482
 
254
- @xarray_dataarray_schema
255
- class EarthLocationArray:
256
- data: Data[CartesianPosLabel, float]
257
483
 
258
- ellipsoid: Attr[str]
484
+ # For now allowing both some of the casacore frames (from "REST" to "TOPO" - all in uppercase) as well as
485
+ # the astropy frames (all in lowercase, taken from the list of SpectralCoord:
486
+ # https://docs.astropy.org/en/stable/coordinates/spectralcoord.html)
487
+ AllowedSpectralCoordFrames = Literal[
488
+ "REST",
489
+ # "LSRK" -> "lsrk",
490
+ # "LSRD" -> "lsrd",
491
+ "BARY",
492
+ "GEO",
493
+ "TOPO",
494
+ # astropy frames
495
+ "gcrs",
496
+ "icrs",
497
+ "hcrs",
498
+ "lsrk",
499
+ "lsrd",
500
+ "lsr",
501
+ ]
502
+
503
+
504
+ @xarray_dataarray_schema
505
+ class SpectralCoordArray:
259
506
  """
260
- ITRF makes use of GRS80 ellipsoid and WGS84 makes use of WGS84 ellipsoid
507
+ Measures array for data variables and attributes that are spectral coordinates.
261
508
  """
262
- units: Attr[list[str]] = ("m", "m", "m")
509
+
510
+ data: Data[ZD, float]
511
+
512
+ units: Attr[UnitsHertz] = ("Hz",)
513
+
514
+ observer: Attr[AllowedSpectralCoordFrames] = "gcrs"
263
515
  """
264
- If the units are a list of strings then it must be the same length as
265
- the last dimension of the data array. This allows for having different
266
- units in the same data array,for example geodetic coordinates could use
267
- ``['rad','rad','m']``.
516
+ Capitalized reference observers are from casacore. TOPO implies creating astropy earth_location.
517
+ Astropy velocity reference frames are lowercase. Note that Astropy does not use the name 'TOPO' (telescope centric)
518
+ rather it assumes if no velocity frame is given that this is the default.
268
519
  """
269
520
 
521
+ type: Attr[SpectralCoord] = "spectral_coord"
522
+
523
+
524
+ AllowedLocationFrames = Literal["ITRF", "GRS80", "WGS84", "WGS72", "Undefined"]
525
+
526
+
527
+ AllowedLocationCoordinateSystems = Literal[
528
+ "geocentric",
529
+ "planetcentric",
530
+ "geodetic",
531
+ "planetodetic",
532
+ "orbital",
533
+ ]
534
+
270
535
 
271
536
  @xarray_dataarray_schema
272
537
  class LocationArray:
273
538
  """
274
- Measure type used for example in field_and_source_xds/OBSERVER_POSITION
539
+ Measure type used for example in antenna_xds/ANTENNA_POSITION, field_and_source_xds/OBSERVER_POSITION
275
540
  Data dimensions can be EllipsoidPosLabel or CartesianPosLabel
276
541
  """
277
542
 
278
543
  data: Data[Union[EllipsoidPosLabel, CartesianPosLabel], float]
279
544
 
280
- ellipsoid: Attr[str]
545
+ units: Attr[UnitsOfLocationInMetersOrRadians]
546
+ """
547
+ If the units are a list of strings then it must be the same length as
548
+ the last dimension of the data array. This allows for having different
549
+ units in the same data array,for example geodetic coordinates could use
550
+ ``['rad','rad','m']``.
551
+ """
552
+
553
+ frame: Attr[AllowedLocationFrames]
281
554
  """
282
- ITRF makes use of GRS80 ellipsoid and WGS84 makes use of WGS84 ellipsoid
555
+ Can be ITRF, GRS80, WGS84, WGS72, Undefined
283
556
  """
284
557
 
558
+ coordinate_system: Attr[AllowedLocationCoordinateSystems]
559
+ """ Can be ``geocentric/planetcentric, geodetic/planetodetic, orbital`` """
560
+
285
561
  origin_object_name: Attr[str]
286
562
  """
287
563
  earth/sun/moon/etc
288
564
  """
289
565
 
290
- coordinate_system: Attr[str]
291
- """ geocentric/planetcentric, geodetic/planetodetic, orbital """
292
-
293
- type: Attr[str] = "location"
566
+ type: Attr[Location] = "location"
294
567
  """ """
295
568
 
296
- units: Attr[list[str]] = ("deg", "deg", "m")
297
- """
298
- If the units are a list of strings then it must be the same length as
299
- the last dimension of the data array. This allows for having different
300
- units in the same data array,for example geodetic coordinates could use
301
- ``['rad','rad','m']``.
302
- """
303
-
304
569
 
305
570
  @xarray_dataarray_schema
306
571
  class EllipsoidPosLocationArray:
@@ -310,23 +575,23 @@ class EllipsoidPosLocationArray:
310
575
 
311
576
  data: Data[EllipsoidPosLabel, float]
312
577
 
313
- ellipsoid: Attr[str]
578
+ frame: Attr[AllowedLocationFrames]
314
579
  """
315
- ITRF makes use of GRS80 ellipsoid and WGS84 makes use of WGS84 ellipsoid
580
+ Can be ITRF, GRS80, WGS84, WGS72
316
581
  """
317
582
 
583
+ coordinate_system: Attr[AllowedLocationCoordinateSystems]
584
+ """ Can be ``geocentric/planetcentric, geodetic/planetodetic, orbital`` """
585
+
318
586
  origin_object_name: Attr[str]
319
587
  """
320
588
  earth/sun/moon/etc
321
589
  """
322
590
 
323
- coordinate_system: Attr[str]
324
- """ geocentric/planetcentric, geodetic/planetodetic, orbital """
325
-
326
- type: Attr[str] = "location"
591
+ type: Attr[Location] = "location"
327
592
  """ """
328
593
 
329
- units: Attr[list[str]] = ("deg", "deg", "m")
594
+ units: Attr[UnitsOfPositionInRadians] = ("rad", "rad", "m")
330
595
  """
331
596
  If the units are a list of strings then it must be the same length as
332
597
  the last dimension of the data array. This allows for having different
@@ -335,280 +600,64 @@ class EllipsoidPosLocationArray:
335
600
  """
336
601
 
337
602
 
338
- @xarray_dataset_schema
339
- class FieldSourceXds:
340
- """
341
- Field positions for each source.
603
+ @xarray_dataarray_schema
604
+ class BaselineArray:
605
+ """Model of the baseline_id coordinate in the main dataset (interferometric data, :py:class:`VisibiiltyXds`)"""
342
606
 
343
- Defines a field position on the sky. For interferometers, this is the correlated field position.
344
- For single dishes, this is the nominal pointing direction.
607
+ data: Data[BaselineId, Union[numpy.int64, numpy.int32]]
608
+ """Unique id for each baseline."""
609
+ long_name: Optional[Attr[str]] = "Baseline ID"
610
+
611
+
612
+ @xarray_dataarray_schema
613
+ class BaselineAntennaNameArray:
614
+ """Array of antenna_name by baseline_id, as used in main_xds and main_sd_xds
615
+ (antenna_name by baseline_id dim"""
616
+
617
+ data: Data[BaselineId, str]
618
+ """Unique id for each baseline."""
619
+ long_name: Optional[Attr[str]] = "Antenna name by baseline_id"
620
+
621
+
622
+ @xarray_dataarray_schema
623
+ class AntennaNameArray:
624
+ """
625
+ Model of the antenna_name coordinate, used in the main dataset (single dish data, :py:class:`VisibiiltyXds`)
626
+ and several sub-datasets such as antenna_xds, pointing_xds, weather_xds, system_calibration_xds, gain_curve_xds, etc.
345
627
  """
346
628
 
347
- source_name: Optional[Coord[Union[ZD, Time], str]]
348
- """ Source name. """
349
- field_name: Optional[Coord[Union[ZD, Time], str]]
350
- """Field name."""
629
+ data: Data[AntennaName, str]
630
+ """Unique name for each antenna(_station)."""
631
+ long_name: Optional[Attr[str]] = "Antenna name"
351
632
 
352
- time: Optional[Coordof[TimeCoordArray]]
353
- """Midpoint of time for which this set of parameters is accurate. Labeled 'time' when interpolated to main time """
354
- time_ephemeris: Optional[Coordof[TimeEphemerisCoordArray]]
355
- """Midpoint of time for which this set of parameters is accurate. Labeled 'time_ephemeris' when not interpolating to main time """
356
633
 
357
- line_label: Optional[Coord[LineLabel, str]]
358
- """ Line labels (for line names and variables). """
634
+ AllowedDopplerTypes = Literal[
635
+ "radio", "optical", "z", "ratio", "true", "relativistic", "beta", "gamma"
636
+ ]
359
637
 
360
- line_names: Optional[
361
- Coord[
362
- Union[
363
- tuple[LineLabel],
364
- tuple[Time, LineLabel],
365
- tuple[TimeEphemeris, LineLabel],
366
- ],
367
- str,
368
- ]
369
- ]
370
- """ Line names (e.g. v=1, J=1-0, SiO). """
371
638
 
372
- FIELD_PHASE_CENTER: Optional[
373
- Data[Union[ZD, tuple[Time], tuple[TimeEphemeris]], SkyCoordOffsetArray]
374
- ]
639
+ @xarray_dataarray_schema
640
+ class DopplerArray:
641
+ """Doppler measure information for the frequency coordinate"""
642
+
643
+ data: Data[ZD, numpy.float64]
644
+
645
+ type: Attr[Doppler] = "doppler"
646
+ """ Coordinate type. Should be ``"spectral_coord"``. """
647
+
648
+ units: Attr[UnitsOfDopplerShift] = ("m/s",)
649
+ """ Units to associate with axis, [ratio]/[m/s]"""
650
+
651
+ doppler_type: Attr[AllowedDopplerTypes] = "radio"
375
652
  """
376
- Offset from the SOURCE_DIRECTION that gives the direction of phase
377
- center for which the fringes have been stopped-that is a point source in
378
- this direction will produce a constant measured phase (page 2 of
379
- https://articles.adsabs.harvard.edu/pdf/1999ASPC..180...79F). For
380
- conversion from MSv2, frame refers column keywords by default. If frame
381
- varies with field, it refers DelayDir_Ref column instead.
653
+ Allowable values: radio, optical, z, ratio, true, relativistic, beta, gamma.
654
+ Astropy only has radio and optical. Using casacore types: https://casadocs.readthedocs.io/en/stable/notebooks/memo-series.html?highlight=Spectral%20Frames#Spectral-Frames
382
655
  """
383
656
 
384
- SOURCE_LOCATION: Optional[
385
- Data[
386
- Union[
387
- ZD,
388
- tuple[Time],
389
- tuple[TimeEphemeris],
390
- ],
391
- SkyCoordArray,
392
- ]
393
- ]
394
- """
395
- CASA Table Cols: RA,DEC,Rho."Astrometric RA and Dec and Geocentric
396
- distance with respect to the observer’s location (Geocentric). "Adjusted
397
- for light-time aberration only. With respect to the reference plane and
398
- equinox of the chosen system (ICRF or FK4/B1950). If the FK4/B1950 frame
399
- output is selected, elliptic aberration terms are added. Astrometric RA/DEC
400
- is generally used when comparing or reducing data against a star catalog."
401
- https://ssd.jpl.nasa.gov/horizons/manual.html : 1. Astrometric RA & DEC
402
- """
403
-
404
- LINE_REST_FREQUENCY: Optional[
405
- Data[
406
- Union[
407
- tuple[LineLabel],
408
- tuple[Time, LineLabel],
409
- tuple[TimeEphemeris, LineLabel],
410
- ],
411
- SpectralCoordArray,
412
- ]
413
- ]
414
- """ Rest frequencies for the transitions. """
415
-
416
- LINE_SYSTEMIC_VELOCITY: Optional[
417
- Data[
418
- Union[
419
- tuple[LineLabel],
420
- tuple[Time, LineLabel],
421
- tuple[TimeEphemeris, LineLabel],
422
- ],
423
- QuantityArray,
424
- ]
425
- ]
426
- """ Systemic velocity at reference """
427
-
428
- SOURCE_RADIAL_VELOCITY: Optional[
429
- Data[Union[ZD, tuple[Time], tuple[TimeEphemeris]], QuantityArray]
430
- ]
431
- """ CASA Table Cols: RadVel. Geocentric distance rate """
432
-
433
- NORTH_POLE_POSITION_ANGLE: Optional[
434
- Data[Union[ZD, tuple[Time], tuple[TimeEphemeris]], QuantityArray]
435
- ]
436
- """ CASA Table cols: NP_ang, "Targets' apparent north-pole position angle (counter-clockwise with respect to direction of true-of-date reference-frame north pole) and angular distance from the sub-observer point (center of disc) at print time. A negative distance indicates the north-pole is on the hidden hemisphere." https://ssd.jpl.nasa.gov/horizons/manual.html : 17. North pole position angle & distance from disc center. """
437
-
438
- NORTH_POLE_ANGULAR_DISTANCE: Optional[
439
- Data[Union[ZD, tuple[Time], tuple[TimeEphemeris]], QuantityArray]
440
- ]
441
- """ CASA Table cols: NP_dist, "Targets' apparent north-pole position angle (counter-clockwise with respect to direction of true-of date reference-frame north pole) and angular distance from the sub-observer point (center of disc) at print time. A negative distance indicates the north-pole is on the hidden hemisphere."https://ssd.jpl.nasa.gov/horizons/manual.html : 17. North pole position angle & distance from disc center. """
442
-
443
- SUB_OBSERVER_DIRECTION: Optional[
444
- Data[
445
- Union[
446
- ZD,
447
- tuple[Time],
448
- tuple[TimeEphemeris],
449
- ],
450
- EllipsoidPosLocationArray,
451
- ]
452
- ]
453
- """ CASA Table cols: DiskLong, DiskLat. "Apparent planetodetic longitude and latitude of the center of the target disc seen by the OBSERVER at print-time. This is not exactly the same as the "nearest point" for a non-spherical target shape (since the center of the disc might not be the point closest to the observer), but is generally very close if not a very irregular body shape. The IAU2009 rotation models are used except for Earth and MOON, which use higher-precision models. For the gas giants Jupiter, Saturn, Uranus and Neptune, IAU2009 longitude is based on the "System III" prime meridian rotation angle of the magnetic field. By contrast, pole direction (thus latitude) is relative to the body dynamical equator. There can be an offset between the magnetic pole and the dynamical pole of rotation. Down-leg light travel-time from target to observer is taken into account. Latitude is the angle between the equatorial plane and perpendicular to the reference ellipsoid of the body and body oblateness thereby included. The reference ellipsoid is an oblate spheroid with a single flatness coefficient in which the y-axis body radius is taken to be the same value as the x-axis radius. Whether longitude is positive to the east or west for the target will be indicated at the end of the output ephemeris." https://ssd.jpl.nasa.gov/horizons/manual.html : 14. Observer sub-longitude & sub-latitude """
454
-
455
- SUB_SOLAR_POSITION: Optional[
456
- Data[
457
- Union[
458
- ZD,
459
- tuple[Time],
460
- tuple[TimeEphemeris],
461
- ],
462
- EllipsoidPosLocationArray,
463
- ]
464
- ]
465
- """ CASA Table cols: Sl_lon, Sl_lat, r. "Heliocentric distance along with "Apparent sub-solar longitude and latitude of the Sun on the target. The apparent planetodetic longitude and latitude of the center of the target disc as seen from the Sun, as seen by the observer at print-time. This is _NOT_ exactly the same as the "sub-solar" (nearest) point for a non-spherical target shape (since the center of the disc seen from the Sun might not be the closest point to the Sun), but is very close if not a highly irregular body shape. Light travel-time from Sun to target and from target to observer is taken into account. Latitude is the angle between the equatorial plane and the line perpendicular to the reference ellipsoid of the body. The reference ellipsoid is an oblate spheroid with a single flatness coefficient in which the y-axis body radius is taken to be the same value as the x-axis radius. Uses IAU2009 rotation models except for Earth and Moon, which uses a higher precision models. Values for Jupiter, Saturn, Uranus and Neptune are Set III, referring to rotation of their magnetic fields. Whether longitude is positive to the east or west for the target will be indicated at the end of the output ephemeris." https://ssd.jpl.nasa.gov/horizons/manual.html : 15. Solar sub-longitude & sub-latitude """
466
-
467
- HELIOCENTRIC_RADIAL_VELOCITY: Optional[
468
- Data[Union[ZD, tuple[Time], tuple[TimeEphemeris]], QuantityArray]
469
- ]
470
- """ CASA Table cols: rdot."The Sun's apparent range-rate relative to the target, as seen by the observer. A positive "rdot" means the target was moving away from the Sun, negative indicates movement toward the Sun." https://ssd.jpl.nasa.gov/horizons/manual.html : 19. Solar range & range-rate (relative to target) """
471
-
472
- OBSERVER_PHASE_ANGLE: Optional[
473
- Data[Union[ZD, tuple[Time], tuple[TimeEphemeris]], QuantityArray]
474
- ]
475
- """ CASA Table cols: phang.""phi" is the true PHASE ANGLE at the observers' location at print time. "PAB-LON" and "PAB-LAT" are the FK4/B1950 or ICRF/J2000 ecliptic longitude and latitude of the phase angle bisector direction; the outward directed angle bisecting the arc created by the apparent vector from Sun to target center and the astrometric vector from observer to target center. For an otherwise uniform ellipsoid, the time when its long-axis is perpendicular to the PAB direction approximately corresponds to lightcurve maximum (or maximum brightness) of the body. PAB is discussed in Harris et al., Icarus 57, 251-258 (1984)." https://ssd.jpl.nasa.gov/horizons/manual.html : Phase angle and bisector """
476
-
477
- OBSERVER_POSITION: Optional[Data[ZD, LocationArray]]
478
- """ Observer location. """
479
-
480
- # --- Attributes ---
481
- DOPPLER_SHIFT_VELOCITY: Optional[Attr[numpy.float64]]
482
- """ Velocity definition of the Doppler shift, e.g., RADIO or OPTICAL velocity in m/s """
483
-
484
- source_model_url: Optional[Attr[str]]
485
- """URL to access source model"""
486
- ephemeris_name: Optional[Attr[str]]
487
- """The name of the ephemeris. For example DE430.
488
-
489
- This can be used with Astropy solar_system_ephemeris.set('DE430'), see
490
- https://docs.astropy.org/en/stable/coordinates/solarsystem.html.
491
- """
492
- is_ephemeris: Attr[bool] = False
493
-
494
- type: Attr[str] = "field_and_source"
495
- """
496
- Type of dataset.
497
- """
498
-
499
- # --- Optional coordinates ---
500
- sky_dir_label: Optional[Coord[SkyDirLabel, str]] = ("ra", "dec")
501
- """ Coordinate labels of sky directions (typically shape 2 and 'ra', 'dec') """
502
- sky_pos_label: Optional[Coord[SkyPosLabel, str]] = ("ra", "dec", "dist")
503
- """ Coordinate lables of sky positions (typically shape 3 and 'ra', 'dec', 'dist') """
504
- ellipsoid_pos_label: Optional[Coord[EllipsoidPosLabel, str]] = (
505
- "lon",
506
- "lat",
507
- "height",
508
- )
509
- """ Coordinate labels of geodetic earth location data (typically shape 3 and 'lon', 'lat', 'height')"""
510
- cartesian_pos_label: Optional[Coord[CartesianPosLabel, str]] = ("x", "y", "z")
511
- """ Coordinate labels of geocentric earth location data (typically shape 3 and 'x', 'y', 'z')"""
512
-
513
-
514
- @dict_schema
515
- class PartitionInfoDict:
516
- # spectral_window_id: missing / remove for good?
517
- spectral_window_name: str
518
- """ Spectral window Name """
519
- # field_id: missing / probably remove for good?
520
- field_name: list[str]
521
- """ List of all field names """
522
- polarization_setup: list[str]
523
- """ List of polrization bases. """
524
- scan_number: list[int]
525
- """ List of scan numbers. """
526
- source_name: list[str]
527
- """ List of source names. """
528
- # source_id: mising / remove for good?
529
- intents: list[str]
530
- """ Infromation in obs_mode column of MSv2 State table. """
531
- taql: Optional[str]
532
- """ The taql query used if converted from MSv2. """
533
- line_name: list[str]
534
- """ Spectral line names """
535
-
536
-
537
- @dict_schema
538
- class ObservationInfoDict:
539
- observer: list
540
- """List of observer names."""
541
- project: str
542
- """Project Code/Project_UID"""
543
- release_date: str
544
- """Project release date. This is the date on which the data may become
545
- public. Format: YYYY-MM-DDTHH:mm:ss.SSS (ISO 8601)"""
546
- execution_block_id: Optional[str]
547
- """ ASDM: Indicates the position of the execution block in the project
548
- (sequential numbering starting at 1). """
549
- execution_block_number: Optional[int]
550
- """ASDM: Indicates the position of the execution block in the project
551
- (sequential numbering starting at 1)."""
552
- execution_block_UID: Optional[str]
553
- """ASDM: The archive’s UID of the execution block."""
554
- session_reference: Optional[str]
555
- """ASDM: The observing session reference."""
556
- observing_script: Optional[str]
557
- """ASDM: The text of the observation script."""
558
- observing_script_UID: Optional[str]
559
- """ASDM: A reference to the Entity which contains the observing script."""
560
- observing_log: Optional[str]
561
- """ASDM: Logs of the observation during this execu- tion block."""
562
-
563
-
564
- @dict_schema
565
- class ProcessorInfoDict:
566
- type: str
567
- """Processor type; reserved keywords include (”CORRELATOR” -
568
- interferometric correlator; ”SPECTROMETER” - single-dish correlator;
569
- ”RADIOMETER” - generic detector/integrator)."""
570
- sub_type: str
571
- """Processor sub-type, e.g. ”GBT” or ”JIVE”."""
572
-
573
-
574
- @xarray_dataarray_schema
575
- class BaselineArray:
576
- """TODO: documentation"""
577
-
578
- data: Data[BaselineId, Union[numpy.int64, numpy.int32]]
579
- """Unique id for each baseline."""
580
- long_name: Optional[Attr[str]] = "Baseline ID"
581
-
582
-
583
- @xarray_dataarray_schema
584
- class BaselineAntennaNameArray:
585
- """Array of antenna_name by baseline_id, as used in main_xds and main_sd_xds
586
- (antenna_name by baseline_id dim"""
587
-
588
- data: Data[BaselineId, str]
589
- """Unique id for each baseline."""
590
- long_name: Optional[Attr[str]] = "Antenna name by baseline_id"
591
-
592
-
593
- @xarray_dataarray_schema
594
- class AntennaNameArray:
595
- """TODO: documentation"""
596
-
597
- data: Data[AntennaName, str]
598
- """Unique name for each antenna(_station)."""
599
- long_name: Optional[Attr[str]] = "Antenna name"
600
-
601
-
602
- @xarray_dataset_schema
603
- class DopplerXds:
604
- """Not specified. Not implemented."""
605
-
606
- pass
607
-
608
657
 
609
658
  @xarray_dataarray_schema
610
659
  class FrequencyArray:
611
- """TODO: documentation"""
660
+ """Frequency coordinate in the main dataset."""
612
661
 
613
662
  data: Data[Frequency, float]
614
663
  """ Time, expressed in SI seconds since the epoch. """
@@ -621,18 +670,20 @@ class FrequencyArray:
621
670
  frequency corresponding to the DC edge of the baseband. Used by the calibration
622
671
  system if a fixed scaling frequency is required or in algorithms to identify the
623
672
  observing band. """
624
- channel_width: Attr[QuantityArray] # Not SpectralCoord, as it is a difference
673
+ channel_width: Attr[
674
+ QuantityInHertzArray
675
+ ] # Not SpectralCoord, as it is a difference
625
676
  """ The nominal channel bandwidth. Same units as data array (see units key). """
626
- doppler: Optional[Attr[DopplerXds]]
677
+ doppler: Optional[Attr[DopplerArray]]
627
678
  """ Doppler tracking information """
628
679
 
629
- type: Attr[str] = "spectral_coord"
680
+ type: Attr[SpectralCoord] = "spectral_coord"
630
681
  """ Coordinate type. Should be ``"spectral_coord"``. """
631
682
  long_name: Optional[Attr[str]] = "Frequency"
632
683
  """ Long-form name to use for axis"""
633
- units: Attr[list[str]] = ("Hz",)
684
+ units: Attr[UnitsHertz] = ("Hz",)
634
685
  """ Units to associate with axis"""
635
- frame: Attr[str] = "icrs"
686
+ observer: Attr[AllowedSpectralCoordFrames] = "icrs"
636
687
  """
637
688
  Astropy velocity reference frames (see :external:ref:`astropy-spectralcoord`).
638
689
  Note that Astropy does not use the name
@@ -648,16 +699,19 @@ class FrequencyCalArray:
648
699
 
649
700
  data: Data[FrequencyCal, float]
650
701
  """ Time, expressed in SI seconds since the epoch. """
651
- reference_value: Attr[SpectralCoordArray]
652
- """ A frequency representative of the spectral window, usually the sky
653
- frequency corresponding to the DC edge of the baseband. Used by the calibration
654
- system if a fixed scaling frequency is required or in algorithms to identify the
655
- observing band. """
656
702
 
657
- type: Attr[str] = "spectral_coord"
658
- units: Attr[list[str]] = ("Hz",)
703
+ type: Attr[SpectralCoord] = "spectral_coord"
704
+ units: Attr[UnitsHertz] = ("Hz",)
659
705
  """ Units to associate with axis"""
660
706
 
707
+ observer: Attr[AllowedSpectralCoordFrames] = "icrs"
708
+ """
709
+ Astropy velocity reference frames (see :external:ref:`astropy-spectralcoord`).
710
+ Note that Astropy does not use the name
711
+ 'topo' (telescope centric) velocity frame, rather it assumes if no velocity
712
+ frame is given that this is the default.
713
+ """
714
+
661
715
 
662
716
  @xarray_dataarray_schema
663
717
  class PolarizationArray:
@@ -700,75 +754,37 @@ class UvwLabelArray:
700
754
 
701
755
  # Data variables
702
756
  @xarray_dataarray_schema
703
- class VisibilityArray:
704
- """TODO: documentation"""
757
+ class FlagArray:
758
+ """
759
+ An array of Boolean values with the same shape as `VISIBILITY`,
760
+ representing the cumulative flags applying to this data matrix. Data are
761
+ flagged bad if the ``FLAG`` array element is ``True``.
762
+ """
705
763
 
706
764
  data: Data[
707
- tuple[Time, BaselineId, Frequency, Polarization],
708
- Union[numpy.complex64, numpy.complex128],
765
+ Union[
766
+ tuple[Time, BaselineId, Frequency, Polarization],
767
+ tuple[Time, BaselineId, Frequency],
768
+ tuple[Time, BaselineId],
769
+ tuple[Time, AntennaName, Frequency, Polarization], # SD
770
+ ],
771
+ bool,
709
772
  ]
710
-
711
773
  time: Coordof[TimeCoordArray]
712
- baseline_id: Coordof[BaselineArray]
713
- polarization: Coordof[PolarizationArray]
774
+ baseline_id: Optional[Coordof[BaselineArray]] # Only IF
775
+ antenna_name: Optional[Coordof[AntennaNameArray]] # Only SD
714
776
  frequency: Coordof[FrequencyArray]
777
+ polarization: Optional[Coordof[PolarizationArray]] = None
778
+ long_name: Optional[Attr[str]] = "Visibility flags"
715
779
 
716
- field_and_source_xds: Attr[FieldSourceXds]
717
- long_name: Optional[Attr[str]] = "Visibility values"
718
- """ Long-form name to use for axis. Should be ``"Visibility values"``"""
719
- units: Attr[list[str]] = ("Jy",)
780
+ allow_mutiple_versions: Optional[Attr[bool]] = True
720
781
 
721
782
 
722
783
  @xarray_dataarray_schema
723
- class SpectrumArray:
724
- """Definition of xr.DataArray for SPECTRUM data (single dish)"""
725
-
726
- data: Data[
727
- tuple[Time, AntennaName, Frequency, Polarization],
728
- Union[numpy.float64, numpy.float32, numpy.float16],
729
- ]
730
-
731
- time: Coordof[TimeCoordArray]
732
- antenna_name: Coordof[AntennaNameArray]
733
- frequency: Coordof[FrequencyArray]
734
- polarization: Coordof[PolarizationArray]
735
-
736
- field_and_source_xds: Attr[FieldSourceXds]
737
- long_name: Optional[Attr[str]] = "Spectrum values"
738
- """ Long-form name to use for axis. Should be ``"Spectrum values"``"""
739
- units: Attr[list[str]] = ("Jy",)
740
-
741
-
742
- @xarray_dataarray_schema
743
- class FlagArray:
744
- """
745
- An array of Boolean values with the same shape as `VISIBILITY`,
746
- representing the cumulative flags applying to this data matrix. Data are
747
- flagged bad if the ``FLAG`` array element is ``True``.
748
- """
749
-
750
- data: Data[
751
- Union[
752
- tuple[Time, BaselineId, Frequency, Polarization],
753
- tuple[Time, BaselineId, Frequency],
754
- tuple[Time, BaselineId],
755
- tuple[Time, AntennaName, Frequency, Polarization], # SD
756
- ],
757
- bool,
758
- ]
759
- time: Coordof[TimeCoordArray]
760
- baseline_id: Optional[Coordof[BaselineArray]] # Only IF
761
- antenna_name: Optional[Coordof[AntennaNameArray]] # Only SD
762
- frequency: Coordof[FrequencyArray]
763
- polarization: Optional[Coordof[PolarizationArray]] = None
764
- long_name: Optional[Attr[str]] = "Visibility flags"
765
-
766
-
767
- @xarray_dataarray_schema
768
- class WeightArray:
769
- """
770
- The weight for each channel, with the same shape as the associated
771
- :py:class:`VisibilityArray`, as assigned by the correlator or processor.
784
+ class WeightArray:
785
+ """
786
+ The weight for each channel, with the same shape as the associated
787
+ :py:class:`VisibilityArray`, as assigned by the correlator or processor.
772
788
 
773
789
  Weight spectrum in ms v2 is renamed weight. Should be calculated as
774
790
  1/sigma^2 (sigma rms noise).
@@ -787,10 +803,21 @@ class WeightArray:
787
803
  time: Coordof[TimeCoordArray]
788
804
  baseline_id: Optional[Coordof[BaselineArray]] # Only IF
789
805
  antenna_name: Optional[Coordof[AntennaNameArray]] # Only SD
790
- frequency: Optional[Coordof[FrequencyArray]] = None
806
+ frequency: Coordof[FrequencyArray] = None
791
807
  polarization: Optional[Coordof[PolarizationArray]] = None
792
808
  long_name: Optional[Attr[str]] = "Visibility weights"
793
809
 
810
+ allow_mutiple_versions: Optional[Attr[bool]] = True
811
+
812
+
813
+ # J2000=>fk5 is used most often. icrs is used less often. Both fk5 and icrs are also borrowed from the field center (to fix
814
+ # ITRF=>J2000). APP has only been seen in WSRT datasets.
815
+ AllowedUvwFrames = Literal[
816
+ "fk5",
817
+ "icrs",
818
+ "APP", # "apparent geocentric position", used in WSRT datasets
819
+ ]
820
+
794
821
 
795
822
  @xarray_dataarray_schema
796
823
  class UvwArray:
@@ -823,14 +850,7 @@ class UvwArray:
823
850
  """
824
851
 
825
852
  data: Data[
826
- Union[
827
- tuple[Time, BaselineId, Frequency, Polarization, UvwLabel],
828
- tuple[Time, BaselineId, Frequency, UvwLabel],
829
- tuple[Time, BaselineId, UvwLabel],
830
- tuple[Time, AntennaName, UvwLabel], # SD
831
- tuple[Time, AntennaName, Frequency, UvwLabel], # SD
832
- tuple[Time, AntennaName, Frequency, Polarization], # SD
833
- ],
853
+ Union[tuple[Time, BaselineId, UvwLabel]],
834
854
  Union[
835
855
  numpy.float16,
836
856
  numpy.float32,
@@ -839,24 +859,29 @@ class UvwArray:
839
859
  ]
840
860
  """Baseline coordinates from ``baseline_antenna2_id`` to ``baseline_antenna1_id``"""
841
861
  time: Coordof[TimeCoordArray]
842
- baseline_id: Optional[Coordof[BaselineArray]] # Only IF
843
- antenna_name: Optional[Coordof[AntennaNameArray]] # Only SD
844
- frequency: Optional[Coordof[FrequencyArray]] = None
845
- polarization: Optional[Coordof[PolarizationArray]] = None
862
+ baseline_id: Optional[Coordof[BaselineArray]]
846
863
  uvw_label: Coordof[UvwLabelArray] = ("u", "v", "w")
864
+
847
865
  long_name: Optional[Attr[str]] = "Baseline coordinates"
848
866
  """ Long-form name to use for axis. Should be ``"Baseline coordinates``"""
849
- units: Attr[list[str]] = ("m",)
867
+
868
+ type: Attr[Literal["uvw"]] = "uvw"
869
+ frame: Attr[AllowedUvwFrames] = "icrs"
870
+ """ To be defined in astropy (see for example https://github.com/astropy/astropy/issues/7766) """
871
+ units: Attr[UnitsMeters] = ("m",)
872
+
873
+ allow_mutiple_versions: Optional[Attr[bool]] = True
850
874
 
851
875
 
852
876
  @xarray_dataarray_schema
853
877
  class TimeSamplingArray:
854
- """TODO: documentation"""
878
+ """
879
+ Model of arrays of measures used in the main dataset for data variables such as TIME_CENTROID and
880
+ TIME_CENTROID_EXTRA_PRECISION.
881
+ """
855
882
 
856
883
  data: Data[
857
884
  Union[
858
- tuple[Time, BaselineId, Frequency, Polarization],
859
- tuple[Time, BaselineId, Frequency],
860
885
  tuple[Time, BaselineId],
861
886
  tuple[Time, AntennaName], # SD
862
887
  ],
@@ -866,21 +891,21 @@ class TimeSamplingArray:
866
891
  time: Coordof[TimeCoordArray]
867
892
  baseline_id: Optional[Coordof[BaselineArray]] # Only IF
868
893
  antenna_name: Optional[Coordof[AntennaNameArray]] # Only SD
869
- frequency: Optional[Coordof[FrequencyArray]] = None
870
- polarization: Optional[Coordof[PolarizationArray]] = None
871
894
 
872
- scale: Attr[str] = "tai"
895
+ scale: Attr[AllowedTimeScales] = "utc"
873
896
  """ Astropy time scales, see :py:class:`astropy.time.Time` """
874
- format: Attr[str] = "unix"
897
+ format: Attr[AllowedTimeFormats] = "unix"
875
898
  """ Astropy format, see :py:class:`astropy.time.Time`. Default seconds from 1970-01-01 00:00:00 UTC """
876
899
 
877
900
  long_name: Optional[Attr[str]] = "Time sampling data"
878
- units: Attr[list[str]] = ("s",)
901
+ units: Attr[UnitsSeconds] = ("s",)
879
902
 
880
903
 
881
904
  @xarray_dataarray_schema
882
905
  class FreqSamplingArray:
883
- """TODO: documentation"""
906
+ """
907
+ Model of frequency related data variables of the main dataset, such as EFFECTIV_CHANNEL_WIDTH and FREQUENCY_CENTROID.
908
+ """
884
909
 
885
910
  data: Data[
886
911
  Union[
@@ -894,15 +919,15 @@ class FreqSamplingArray:
894
919
  """
895
920
  Data about frequency sampling, such as centroid or integration
896
921
  time. Concrete function depends on concrete data array within
897
- :py:class:`VisibilityXds`.
922
+ :py:class:`VisibilityXds` or :py:class:`SpectrumXds`.
898
923
  """
899
924
  frequency: Coordof[FrequencyArray]
900
925
  time: Optional[Coordof[TimeCoordArray]] = None
901
926
  baseline_id: Optional[Coordof[BaselineArray]] = None
902
927
  polarization: Optional[Coordof[PolarizationArray]] = None
903
928
  long_name: Optional[Attr[str]] = "Frequency sampling data"
904
- units: Attr[list[str]] = ("Hz",)
905
- frame: Attr[str] = "icrs"
929
+ units: Attr[UnitsHertz] = ("Hz",)
930
+ observer: Attr[AllowedSpectralCoordFrames] = "icrs"
906
931
  """
907
932
  Astropy velocity reference frames (see :external:ref:`astropy-spectralcoord`).
908
933
  Note that Astropy does not use the name
@@ -911,11 +936,311 @@ class FreqSamplingArray:
911
936
  """
912
937
 
913
938
 
939
+ # Define FieldAndSourceXds dataset already here, as it is needed in the
940
+ # definition of VisibilityArray
941
+ @xarray_dataset_schema
942
+ class FieldSourceXds:
943
+ """
944
+ Field positions for each source.
945
+
946
+ Defines a field position on the sky. For interferometers, this is the correlated field position.
947
+ For single dishes, this is the nominal pointing direction.
948
+ """
949
+
950
+ source_name: Optional[Coord[Union[ZD, Time], str]]
951
+ """ Source name. """
952
+ field_name: Optional[Coord[Union[ZD, Time], str]]
953
+ """Field name."""
954
+
955
+ time: Optional[Coordof[TimeInterpolatedCoordArray]]
956
+ """Midpoint of time for which this set of parameters is accurate. Labeled 'time' when interpolated to main time """
957
+ time_ephemeris: Optional[Coordof[TimeEphemerisCoordArray]]
958
+ """Midpoint of time for which this set of parameters is accurate. Labeled 'time_ephemeris' when not interpolating to main time """
959
+
960
+ line_label: Optional[Coord[LineLabel, str]]
961
+ """ Line labels (for line names and variables). """
962
+
963
+ line_names: Optional[
964
+ Coord[
965
+ Union[
966
+ tuple[LineLabel],
967
+ tuple[Time, LineLabel],
968
+ tuple[TimeEphemeris, LineLabel],
969
+ ],
970
+ str,
971
+ ]
972
+ ]
973
+ """ Line names (e.g. v=1, J=1-0, SiO). """
974
+
975
+ FIELD_PHASE_CENTER: Optional[
976
+ Data[Union[ZD, tuple[Time], tuple[TimeEphemeris]], SkyCoordArray]
977
+ ]
978
+ """
979
+ Offset from the SOURCE_DIRECTION that gives the direction of phase
980
+ center for which the fringes have been stopped-that is a point source in
981
+ this direction will produce a constant measured phase (page 2 of
982
+ https://articles.adsabs.harvard.edu/pdf/1999ASPC..180...79F). For
983
+ conversion from MSv2, frame refers column keywords by default. If frame
984
+ varies with field, it refers DelayDir_Ref column instead.
985
+ """
986
+
987
+ FIELD_REFERENCE_CENTER: Optional[
988
+ Data[Union[ZD, tuple[Time], tuple[TimeEphemeris]], SkyCoordArray]
989
+ ]
990
+ """
991
+ Used in single-dish to record the associated reference direction if positionswitching
992
+ been applied. For conversion from MSv2, frame refers column keywords by default. If
993
+ frame varies with field, it refers DelayDir_Ref column instead.
994
+ """
995
+
996
+ SOURCE_LOCATION: Optional[
997
+ Data[
998
+ Union[
999
+ ZD,
1000
+ tuple[Time],
1001
+ tuple[TimeEphemeris],
1002
+ ],
1003
+ SkyCoordArray,
1004
+ ]
1005
+ ]
1006
+ """
1007
+ CASA Table Cols: RA,DEC,Rho."Astrometric RA and Dec and Geocentric
1008
+ distance with respect to the observer’s location (Geocentric). "Adjusted
1009
+ for light-time aberration only. With respect to the reference plane and
1010
+ equinox of the chosen system (ICRF or FK4/B1950). If the FK4/B1950 frame
1011
+ output is selected, elliptic aberration terms are added. Astrometric RA/DEC
1012
+ is generally used when comparing or reducing data against a star catalog."
1013
+ https://ssd.jpl.nasa.gov/horizons/manual.html : 1. Astrometric RA & DEC
1014
+ """
1015
+
1016
+ LINE_REST_FREQUENCY: Optional[
1017
+ Data[
1018
+ Union[
1019
+ tuple[LineLabel],
1020
+ tuple[Time, LineLabel],
1021
+ tuple[TimeEphemeris, LineLabel],
1022
+ ],
1023
+ SpectralCoordArray,
1024
+ ]
1025
+ ]
1026
+ """ Rest frequencies for the transitions. """
1027
+
1028
+ LINE_SYSTEMIC_VELOCITY: Optional[
1029
+ Data[
1030
+ Union[
1031
+ tuple[LineLabel],
1032
+ tuple[Time, LineLabel],
1033
+ tuple[TimeEphemeris, LineLabel],
1034
+ ],
1035
+ QuantityInMetersPerSecondArray,
1036
+ ]
1037
+ ]
1038
+ """ Systemic velocity at reference """
1039
+
1040
+ SOURCE_RADIAL_VELOCITY: Optional[
1041
+ Data[
1042
+ Union[ZD, tuple[Time], tuple[TimeEphemeris]], QuantityInMetersPerSecondArray
1043
+ ]
1044
+ ]
1045
+ """ CASA Table Cols: RadVel. Geocentric distance rate """
1046
+
1047
+ NORTH_POLE_POSITION_ANGLE: Optional[
1048
+ Data[Union[ZD, tuple[Time], tuple[TimeEphemeris]], QuantityInRadiansArray]
1049
+ ]
1050
+ """ CASA Table cols: NP_ang, "Targets' apparent north-pole position angle (counter-clockwise with respect to direction of true-of-date reference-frame north pole) and angular distance from the sub-observer point (center of disc) at print time. A negative distance indicates the north-pole is on the hidden hemisphere." https://ssd.jpl.nasa.gov/horizons/manual.html : 17. North pole position angle & distance from disc center. """
1051
+
1052
+ NORTH_POLE_ANGULAR_DISTANCE: Optional[
1053
+ Data[Union[ZD, tuple[Time], tuple[TimeEphemeris]], QuantityInRadiansArray]
1054
+ ]
1055
+ """ CASA Table cols: NP_dist, "Targets' apparent north-pole position angle (counter-clockwise with respect to direction of true-of date reference-frame north pole) and angular distance from the sub-observer point (center of disc) at print time. A negative distance indicates the north-pole is on the hidden hemisphere."https://ssd.jpl.nasa.gov/horizons/manual.html : 17. North pole position angle & distance from disc center. """
1056
+
1057
+ SUB_OBSERVER_DIRECTION: Optional[
1058
+ Data[
1059
+ Union[
1060
+ ZD,
1061
+ tuple[Time],
1062
+ tuple[TimeEphemeris],
1063
+ ],
1064
+ EllipsoidPosLocationArray,
1065
+ ]
1066
+ ]
1067
+ """ CASA Table cols: DiskLong, DiskLat. "Apparent planetodetic longitude and latitude of the center of the target disc seen by the OBSERVER at print-time. This is not exactly the same as the "nearest point" for a non-spherical target shape (since the center of the disc might not be the point closest to the observer), but is generally very close if not a very irregular body shape. The IAU2009 rotation models are used except for Earth and MOON, which use higher-precision models. For the gas giants Jupiter, Saturn, Uranus and Neptune, IAU2009 longitude is based on the "System III" prime meridian rotation angle of the magnetic field. By contrast, pole direction (thus latitude) is relative to the body dynamical equator. There can be an offset between the magnetic pole and the dynamical pole of rotation. Down-leg light travel-time from target to observer is taken into account. Latitude is the angle between the equatorial plane and perpendicular to the reference ellipsoid of the body and body oblateness thereby included. The reference ellipsoid is an oblate spheroid with a single flatness coefficient in which the y-axis body radius is taken to be the same value as the x-axis radius. Whether longitude is positive to the east or west for the target will be indicated at the end of the output ephemeris." https://ssd.jpl.nasa.gov/horizons/manual.html : 14. Observer sub-longitude & sub-latitude """
1068
+
1069
+ SUB_SOLAR_POSITION: Optional[
1070
+ Data[
1071
+ Union[
1072
+ ZD,
1073
+ tuple[Time],
1074
+ tuple[TimeEphemeris],
1075
+ ],
1076
+ EllipsoidPosLocationArray,
1077
+ ]
1078
+ ]
1079
+ """ CASA Table cols: Sl_lon, Sl_lat, r. "Heliocentric distance along with "Apparent sub-solar longitude and latitude of the Sun on the target. The apparent planetodetic longitude and latitude of the center of the target disc as seen from the Sun, as seen by the observer at print-time. This is _NOT_ exactly the same as the "sub-solar" (nearest) point for a non-spherical target shape (since the center of the disc seen from the Sun might not be the closest point to the Sun), but is very close if not a highly irregular body shape. Light travel-time from Sun to target and from target to observer is taken into account. Latitude is the angle between the equatorial plane and the line perpendicular to the reference ellipsoid of the body. The reference ellipsoid is an oblate spheroid with a single flatness coefficient in which the y-axis body radius is taken to be the same value as the x-axis radius. Uses IAU2009 rotation models except for Earth and Moon, which uses a higher precision models. Values for Jupiter, Saturn, Uranus and Neptune are Set III, referring to rotation of their magnetic fields. Whether longitude is positive to the east or west for the target will be indicated at the end of the output ephemeris." https://ssd.jpl.nasa.gov/horizons/manual.html : 15. Solar sub-longitude & sub-latitude """
1080
+
1081
+ HELIOCENTRIC_RADIAL_VELOCITY: Optional[
1082
+ Data[
1083
+ Union[ZD, tuple[Time], tuple[TimeEphemeris]], QuantityInMetersPerSecondArray
1084
+ ]
1085
+ ]
1086
+ """ CASA Table cols: rdot."The Sun's apparent range-rate relative to the target, as seen by the observer. A positive "rdot" means the target was moving away from the Sun, negative indicates movement toward the Sun." https://ssd.jpl.nasa.gov/horizons/manual.html : 19. Solar range & range-rate (relative to target) """
1087
+
1088
+ OBSERVER_PHASE_ANGLE: Optional[
1089
+ Data[Union[ZD, tuple[Time], tuple[TimeEphemeris]], QuantityInRadiansArray]
1090
+ ]
1091
+ """ CASA Table cols: phang.""phi" is the true PHASE ANGLE at the observers' location at print time. "PAB-LON" and "PAB-LAT" are the FK4/B1950 or ICRF/J2000 ecliptic longitude and latitude of the phase angle bisector direction; the outward directed angle bisecting the arc created by the apparent vector from Sun to target center and the astrometric vector from observer to target center. For an otherwise uniform ellipsoid, the time when its long-axis is perpendicular to the PAB direction approximately corresponds to lightcurve maximum (or maximum brightness) of the body. PAB is discussed in Harris et al., Icarus 57, 251-258 (1984)." https://ssd.jpl.nasa.gov/horizons/manual.html : Phase angle and bisector """
1092
+
1093
+ OBSERVER_POSITION: Optional[Data[ZD, LocationArray]]
1094
+ """ Observer location. """
1095
+
1096
+ # --- Attributes ---
1097
+ doppler_shift_velocity: Optional[Attr[UnitsOfDopplerShift]]
1098
+ """ Velocity definition of the Doppler shift, e.g., RADIO or OPTICAL velocity in m/s """
1099
+
1100
+ source_model_url: Optional[Attr[str]]
1101
+ """URL to access source model"""
1102
+ ephemeris_name: Optional[Attr[str]]
1103
+ """The name of the ephemeris. For example DE430.
1104
+
1105
+ This can be used with Astropy solar_system_ephemeris.set('DE430'), see
1106
+ https://docs.astropy.org/en/stable/coordinates/solarsystem.html.
1107
+ """
1108
+ is_ephemeris: Attr[bool] = False
1109
+
1110
+ type: Attr[Literal["field_and_source"]] = "field_and_source"
1111
+ """
1112
+ Type of dataset.
1113
+ """
1114
+
1115
+ # --- Optional coordinates ---
1116
+ sky_dir_label: Optional[Coord[SkyDirLabel, str]] = ("ra", "dec")
1117
+ """ Coordinate labels of sky directions (typically shape 2 and 'ra', 'dec') """
1118
+ sky_pos_label: Optional[Coord[SkyPosLabel, str]] = ("ra", "dec", "dist")
1119
+ """ Coordinate lables of sky positions (typically shape 3 and 'ra', 'dec', 'dist') """
1120
+ ellipsoid_pos_label: Optional[Coord[EllipsoidPosLabel, str]] = (
1121
+ "lon",
1122
+ "lat",
1123
+ "height",
1124
+ )
1125
+ """ Coordinate labels of geodetic earth location data (typically shape 3 and 'lon', 'lat', 'height')"""
1126
+ cartesian_pos_label: Optional[Coord[CartesianPosLabel, str]] = ("x", "y", "z")
1127
+ """ Coordinate labels of geocentric earth location data (typically shape 3 and 'x', 'y', 'z')"""
1128
+
1129
+
1130
+ @xarray_dataarray_schema
1131
+ class SpectrumArray:
1132
+ """Definition of xr.DataArray for SPECTRUM data (single dish)"""
1133
+
1134
+ data: Data[
1135
+ tuple[Time, AntennaName, Frequency, Polarization],
1136
+ Union[numpy.float64, numpy.float32, numpy.float16],
1137
+ ]
1138
+
1139
+ time: Coordof[TimeCoordArray]
1140
+ antenna_name: Coordof[AntennaNameArray]
1141
+ frequency: Coordof[FrequencyArray]
1142
+ polarization: Coordof[PolarizationArray]
1143
+
1144
+ field_and_source_xds: Attr[FieldSourceXds]
1145
+ long_name: Optional[Attr[str]] = "Spectrum values"
1146
+ """ Long-form name to use for axis. Should be ``"Spectrum values"``"""
1147
+ units: Attr[list[str]] = ("Jy",)
1148
+
1149
+
1150
+ @xarray_dataarray_schema
1151
+ class VisibilityArray:
1152
+ """Visibility data array in main dataset (interferometric data, :py:class:`VisibiiltyXds`)"""
1153
+
1154
+ data: Data[
1155
+ tuple[Time, BaselineId, Frequency, Polarization],
1156
+ Union[numpy.complex64, numpy.complex128],
1157
+ ]
1158
+
1159
+ time: Coordof[TimeCoordArray]
1160
+ baseline_id: Coordof[BaselineArray]
1161
+ polarization: Coordof[PolarizationArray]
1162
+ frequency: Coordof[FrequencyArray]
1163
+
1164
+ field_and_source_xds: Attr[FieldSourceXds]
1165
+ long_name: Optional[Attr[str]] = "Visibility values"
1166
+ """ Long-form name to use for axis. Should be ``"Visibility values"``"""
1167
+ units: Attr[list[str]] = ("Jy",)
1168
+
1169
+ allow_mutiple_versions: Optional[Attr[bool]] = True
1170
+
1171
+
1172
+ # Info dicts
1173
+
1174
+
1175
+ @dict_schema
1176
+ class PartitionInfoDict:
1177
+ # spectral_window_id: missing / remove for good?
1178
+ spectral_window_name: str
1179
+ """ Spectral window Name """
1180
+ # field_id: missing / probably remove for good?
1181
+ field_name: list[str]
1182
+ """ List of all field names """
1183
+ polarization_setup: list[str]
1184
+ """ List of polrization bases. """
1185
+ scan_number: list[int]
1186
+ """ List of scan numbers. """
1187
+ source_name: list[str]
1188
+ """ List of source names. """
1189
+ # source_id: mising / remove for good?
1190
+ intents: list[str]
1191
+ """ Infromation in obs_mode column of MSv2 State table. """
1192
+ taql: Optional[str]
1193
+ """ The taql query used if converted from MSv2. """
1194
+ line_name: list[str]
1195
+ """ Spectral line names """
1196
+
1197
+
1198
+ @dict_schema
1199
+ class ObservationInfoDict:
1200
+ observer: list
1201
+ """List of observer names."""
1202
+ project: str
1203
+ """Project Code/Project_UID"""
1204
+ release_date: str
1205
+ """Project release date. This is the date on which the data may become
1206
+ public. Format: YYYY-MM-DDTHH:mm:ss.SSS (ISO 8601)"""
1207
+ execution_block_id: Optional[str]
1208
+ """ ASDM: Indicates the position of the execution block in the project
1209
+ (sequential numbering starting at 1). """
1210
+ execution_block_number: Optional[int]
1211
+ """ASDM: Indicates the position of the execution block in the project
1212
+ (sequential numbering starting at 1)."""
1213
+ execution_block_UID: Optional[str]
1214
+ """ASDM: The archive’s UID of the execution block."""
1215
+ session_reference: Optional[str]
1216
+ """ASDM: The observing session reference."""
1217
+ observing_script: Optional[str]
1218
+ """ASDM: The text of the observation script."""
1219
+ observing_script_UID: Optional[str]
1220
+ """ASDM: A reference to the Entity which contains the observing script."""
1221
+ observing_log: Optional[str]
1222
+ """ASDM: Logs of the observation during this execu- tion block."""
1223
+
1224
+
1225
+ @dict_schema
1226
+ class ProcessorInfoDict:
1227
+ type: str
1228
+ """Processor type; reserved keywords include (”CORRELATOR” -
1229
+ interferometric correlator; ”SPECTROMETER” - single-dish correlator;
1230
+ ”RADIOMETER” - generic detector/integrator)."""
1231
+ sub_type: str
1232
+ """Processor sub-type, e.g. ”GBT” or ”JIVE”."""
1233
+
1234
+
914
1235
  # Data Sets
915
1236
 
916
1237
 
917
1238
  @xarray_dataset_schema
918
1239
  class AntennaXds:
1240
+ """
1241
+ Antenna dataset: global antenna properties for each antenna.
1242
+ """
1243
+
919
1244
  # Coordinates
920
1245
  antenna_name: Coordof[AntennaNameArray]
921
1246
  """ Antenna name """
@@ -931,11 +1256,9 @@ class AntennaXds:
931
1256
  ”SPACE-HALCA” - specific orientation model."""
932
1257
  telescope_name: Coord[AntennaName, str]
933
1258
  """ Useful when data is combined from mutiple arrays for example ACA + ALMA. """
934
- # TODO: receptor_label, polarization_type, sky_dir_label set as optional
935
- # for datasets like test_alma_ephemris_mosaic. See also BEAM_OFFSET below.
936
- receptor_label: Optional[Coord[ReceptorLabel, str]]
1259
+ receptor_label: Coord[ReceptorLabel, str]
937
1260
  """ Names of receptors """
938
- polarization_type: Optional[Coord[tuple[AntennaName, ReceptorLabel], str]]
1261
+ polarization_type: Coord[tuple[AntennaName, ReceptorLabel], str]
939
1262
  """ Polarization type to which each receptor responds (e.g. ”R”,”L”,”X” or ”Y”).
940
1263
  This is the receptor polarization type as recorded in the final correlated data (e.g. ”RR”); i.e.
941
1264
  as measured after all polarization combiners. ['X','Y'], ['R','L'] """
@@ -943,50 +1266,36 @@ class AntennaXds:
943
1266
  """ (x,y,z) - either cartesian or ellipsoid """
944
1267
  ellipsoid_pos_label: Optional[Coord[EllipsoidPosLabel, str]]
945
1268
  """ (lon, lat, dist) - either cartesian or ellipsoid"""
946
- sky_dir_label: Optional[Coord[SkyDirLabel, str]]
947
- """ ra, dec """
948
1269
 
949
1270
  # Data variables
950
- ANTENNA_POSITION: Data[
951
- Union[
952
- tuple[AntennaName, EllipsoidPosLabel], tuple[AntennaName, CartesianPosLabel]
953
- ],
954
- QuantityArray,
955
- ] # EarthLocationArray
1271
+ ANTENNA_POSITION: Data[tuple[AntennaName], LocationArray]
956
1272
  """
957
1273
  In a right-handed frame, X towards the intersection of the equator and
958
1274
  the Greenwich meridian, Z towards the pole.
959
1275
  """
960
- ANTENNA_FEED_OFFSET: Data[
961
- Union[
962
- tuple[AntennaName, EllipsoidPosLabel], tuple[AntennaName, CartesianPosLabel]
963
- ],
964
- QuantityArray,
965
- ]
966
- """
967
- Offset of feed relative to position (``Antenna_Table.offset + Feed_Table.position``).
1276
+ ANTENNA_DISH_DIAMETER: Optional[Data[tuple[AntennaName], QuantityInMetersArray]]
968
1277
  """
969
- ANTENNA_DISH_DIAMETER: Optional[Data[tuple[AntennaName], QuantityArray]]
970
- """
971
- Nominal diameter of dish, as opposed to the effective diameter.
1278
+ The diameter of the main reflector (or the largest dimension for non-circular apertures).
972
1279
  """
973
1280
  ANTENNA_EFFECTIVE_DISH_DIAMETER: Optional[
974
- Data[tuple[AntennaName, ReceptorLabel, SkyDirLabel], QuantityArray]
1281
+ Data[tuple[AntennaName], QuantityInMetersArray]
975
1282
  ]
976
- """ Airy Disk Model .... """
1283
+ """ Effective dish diameter used in computing beam model (such as airy disk). """
977
1284
 
978
- # TODO: setting BEAM_OFFSET and RECEPTOR_ANGLE as optional for now, as it
979
- # is not present in some datasets (example: test_alma_ephemris_mosaic)
980
- BEAM_OFFSET: Optional[Data[tuple[AntennaName, ReceptorLabel], SkyCoordArray]]
1285
+ ANTENNA_BLOCKAGE: Optional[Data[tuple[AntennaName], QuantityInMetersArray]]
981
1286
  """
982
- Beam position offset, as defined on the sky but in the antenna
983
- reference frame.
1287
+ Blockage caused by secondary reflector used in computing beam model (such as airy disk).
984
1288
  """
985
- RECEPTOR_ANGLE: Optional[Data[tuple[AntennaName, ReceptorLabel], QuantityArray]]
1289
+
1290
+ # TODO: setting BEAM_OFFSET and RECEPTOR_ANGLE as optional for now, as it
1291
+ # is not present in some datasets (example: test_alma_ephemris_mosaic)
1292
+ ANTENNA_RECEPTOR_ANGLE: Optional[
1293
+ Data[tuple[AntennaName, ReceptorLabel], QuantityInRadiansArray]
1294
+ ]
986
1295
  """
987
1296
  Polarization reference angle. Converts into parallactic angle in the sky domain.
988
1297
  """
989
- FOCUS_LENGTH: Optional[Data[tuple[AntennaName], QuantityArray]]
1298
+ ANTENNA_FOCUS_LENGTH: Optional[Data[tuple[AntennaName], QuantityInMetersArray]]
990
1299
  """
991
1300
  Focus length. As defined along the optical axis of the antenna.
992
1301
  """
@@ -1002,7 +1311,7 @@ class AntennaXds:
1002
1311
  """
1003
1312
  relocatable_antennas: Optional[Attr[bool]]
1004
1313
  """ Can the antennas be moved (ALMA, VLA, NOEMA) """
1005
- type: Attr[str] = "antenna"
1314
+ type: Attr[Literal["antenna"]] = "antenna"
1006
1315
  """
1007
1316
  Type of dataset. Expected to be ``antenna``
1008
1317
  """
@@ -1029,8 +1338,6 @@ class GainCurveXds:
1029
1338
  ”SPACE-HALCA” - specific orientation model."""
1030
1339
  telescope_name: Coord[AntennaName, str]
1031
1340
  """ Useful when data is combined from mutiple arrays for example ACA + ALMA. """
1032
- # TODO: receptor_label, polarization_type, sky_dir_label set as optional
1033
- # for datasets like test_alma_ephemris_mosaic. See also BEAM_OFFSET below.
1034
1341
  receptor_label: Coord[ReceptorLabel, str]
1035
1342
  """ Names of receptors """
1036
1343
  polarization_type: Optional[Coord[tuple[AntennaName, ReceptorLabel], str]]
@@ -1045,19 +1352,23 @@ class GainCurveXds:
1045
1352
  ”VOLTAGE(EL)” - Voltage as a function of elevation;
1046
1353
  ”VOLTAGE(ZA)” - Voltage as a function of zenith angle). See https://casacore.github.io/casacore-notes/265.pdf
1047
1354
  """
1355
+ poly_term: Coord[PolyTerm, int]
1356
+ """Term orders in gain curve polynomial"""
1048
1357
 
1049
- GAIN_CURVE_SENSITIVITY: Data[tuple[AntennaName, ReceptorLabel], numpy.float32]
1050
- """ Sensitivity of the antenna expressed in K/Jy. This is what AIPS calls “DPFU”. """
1051
- GAIN_CURVE: Data[tuple[AntennaName, PolyTerm, ReceptorLabel], numpy.float32]
1358
+ GAIN_CURVE: Data[tuple[AntennaName, PolyTerm, ReceptorLabel], numpy.float64]
1052
1359
  """ Coefficients of the polynomial that describes the (power or voltage) gain. """
1053
- GAIN_CURVE_INTERVAL: Data[tuple[AntennaName], QuantityArray]
1360
+ GAIN_CURVE_INTERVAL: Data[tuple[AntennaName], QuantityInSecondsArray]
1054
1361
  """ Time interval. """
1362
+ GAIN_CURVE_SENSITIVITY: Data[
1363
+ tuple[AntennaName, ReceptorLabel], QuantityInKelvinPerJanskyArray
1364
+ ]
1365
+ """ Sensitivity of the antenna expressed in K/Jy. This is what AIPS calls “DPFU”. """
1055
1366
 
1056
1367
  measured_date: Attr[str]
1057
1368
  """
1058
1369
  Date gain curve was measured. Format: YYYY-MM-DDTHH:mm:ss.SSS (ISO 8601)
1059
1370
  """
1060
- type: Attr[str] = "gain_curve"
1371
+ type: Attr[Literal["gain_curve"]] = "gain_curve"
1061
1372
  """
1062
1373
  Type of dataset. Expected to be ``gain_curve``
1063
1374
  """
@@ -1065,6 +1376,9 @@ class GainCurveXds:
1065
1376
 
1066
1377
  @xarray_dataset_schema
1067
1378
  class PhaseCalibrationXds:
1379
+ """
1380
+ Phase calibration dataset: signal chain phase calibration measurements.
1381
+ """
1068
1382
 
1069
1383
  # Coordinates
1070
1384
  antenna_name: Coordof[AntennaNameArray]
@@ -1081,15 +1395,13 @@ class PhaseCalibrationXds:
1081
1395
  ”SPACE-HALCA” - specific orientation model."""
1082
1396
  telescope_name: Coord[AntennaName, str]
1083
1397
  """ Useful when data is combined from mutiple arrays for example ACA + ALMA. """
1084
- # TODO: receptor_label, polarization_type, sky_dir_label set as optional
1085
- # for datasets like test_alma_ephemris_mosaic. See also BEAM_OFFSET below.
1086
- receptor_label: Optional[Coord[ReceptorLabel, str]]
1398
+ receptor_label: Coord[ReceptorLabel, str]
1087
1399
  """ Names of receptors """
1088
1400
  polarization_type: Optional[Coord[tuple[AntennaName, ReceptorLabel], str]]
1089
1401
  """ Polarization type to which each receptor responds (e.g. ”R”,”L”,”X” or ”Y”).
1090
1402
  This is the receptor polarization type as recorded in the final correlated data (e.g. ”RR”); i.e.
1091
1403
  as measured after all polarization combiners. ['X','Y'], ['R','L'] """
1092
- time: Optional[Coordof[TimeCoordArray]]
1404
+ time: Optional[Coordof[TimeInterpolatedCoordArray]]
1093
1405
  """ Time for VLBI phase cal"""
1094
1406
  time_phase_cal: Optional[Coord[TimePhaseCal, numpy.float64]]
1095
1407
  """ Time for VLBI phase cal"""
@@ -1114,7 +1426,7 @@ for each of the measured tones. See https://casacore.github.io/casacore-notes/26
1114
1426
  """
1115
1427
  PHASE_CAL_CABLE_CAL: Data[
1116
1428
  Union[tuple[AntennaName, Time], tuple[AntennaName, TimePhaseCal]],
1117
- QuantityArray,
1429
+ QuantityInSecondsArray,
1118
1430
  ]
1119
1431
  """
1120
1432
  Cable calibration measurement. This is a measurement of the delay in the cable that provides the
@@ -1123,7 +1435,7 @@ multiple receptors) so this is provided as a simple scalar. See https://casacore
1123
1435
  """
1124
1436
  PHASE_CAL_INTERVAL: Data[
1125
1437
  Union[tuple[AntennaName, Time], tuple[AntennaName, TimePhaseCal]],
1126
- QuantityArray,
1438
+ QuantityInSecondsArray,
1127
1439
  ]
1128
1440
  """
1129
1441
  Time interval. See https://casacore.github.io/casacore-notes/265.pdf
@@ -1133,13 +1445,13 @@ multiple receptors) so this is provided as a simple scalar. See https://casacore
1133
1445
  tuple[AntennaName, Time, ReceptorLabel, ToneLabel],
1134
1446
  tuple[AntennaName, TimePhaseCal, ReceptorLabel, ToneLabel],
1135
1447
  ],
1136
- QuantityArray,
1448
+ QuantityInHertzArray,
1137
1449
  ]
1138
1450
  """
1139
1451
  The sky frequencies of each measured phase-cal tone. See https://casacore.github.io/casacore-notes/265.pdf
1140
1452
  """
1141
1453
 
1142
- type: Attr[str] = "phase_calibration"
1454
+ type: Attr[Literal["phase_calibration"]] = "phase_calibration"
1143
1455
  """
1144
1456
  Type of dataset. Expected to be ``phase_calibration``
1145
1457
  """
@@ -1147,39 +1459,111 @@ multiple receptors) so this is provided as a simple scalar. See https://casacore
1147
1459
 
1148
1460
  @xarray_dataset_schema
1149
1461
  class WeatherXds:
1150
- """Weather. Contains station positions and time-dependent mean external
1151
- atmosphere and weather information"""
1462
+ """
1463
+ Weather dataset: station positions and time-dependent mean external atmosphere and weather information
1464
+ """
1152
1465
 
1153
1466
  # Coordinates
1154
1467
  station_name: Coord[StationName, str]
1155
1468
  """ Station identifier """
1156
- time: Coordof[TimeCoordArray]
1157
- """ Mid-point of the time interval """
1469
+ time: Optional[Coordof[TimeInterpolatedCoordArray]]
1470
+ """ Mid-point of the time interval. Labeled 'time' when interpolated to main time axis """
1471
+ time_weather: Optional[Coordof[TimeWeatherCoordArray]]
1472
+ """ Mid-point of the time interval. Labeled 'time_cal' when not interpolated to main time axis """
1158
1473
  antenna_name: Optional[Coordof[AntennaNameArray]]
1159
1474
  """ Antenna identifier """
1475
+ ellipsoid_pos_label: Optional[Coord[EllipsoidPosLabel, str]] = (
1476
+ "lon",
1477
+ "lat",
1478
+ "height",
1479
+ )
1480
+ """ Coordinate labels of geodetic earth location data (typically shape 3 and 'lon', 'lat', 'height')"""
1481
+ cartesian_pos_label: Optional[Coord[CartesianPosLabel, str]] = ("x", "y", "z")
1482
+ """ Coordinate labels of geocentric earth location data (typically shape 3 and 'x', 'y', 'z')"""
1160
1483
 
1161
1484
  # Data variables (all optional)
1162
- H2O: Optional[Data[tuple[StationName, Time], QuantityArray]] = None
1485
+ H2O: Optional[
1486
+ Data[
1487
+ Union[tuple[StationName, Time], tuple[StationName, TimeWeather]],
1488
+ QuantityInPerSquareMetersArray,
1489
+ ]
1490
+ ] = None
1163
1491
  """ Average column density of water """
1164
- IONOS_ELECTRON: Optional[Data[tuple[StationName, Time], QuantityArray]] = None
1492
+ IONOS_ELECTRON: Optional[
1493
+ Data[
1494
+ Union[
1495
+ tuple[StationName, Time],
1496
+ tuple[StationName, TimeWeather],
1497
+ ],
1498
+ QuantityInPerSquareMetersArray,
1499
+ ]
1500
+ ] = None
1165
1501
  """ Average column density of electrons """
1166
- PRESSURE: Optional[Data[tuple[StationName, Time], QuantityArray]] = None
1502
+ PRESSURE: Optional[
1503
+ Data[
1504
+ Union[
1505
+ tuple[StationName, Time],
1506
+ tuple[StationName, TimeWeather],
1507
+ ],
1508
+ QuantityInPascalArray,
1509
+ ]
1510
+ ] = None
1167
1511
  """ Ambient atmospheric pressure """
1168
- REL_HUMIDITY: Optional[Data[tuple[StationName, Time], QuantityArray]] = None
1512
+ REL_HUMIDITY: Optional[
1513
+ Data[
1514
+ Union[
1515
+ tuple[StationName, Time],
1516
+ tuple[StationName, TimeWeather],
1517
+ ],
1518
+ numpy.float64,
1519
+ ]
1520
+ ] = None
1169
1521
  """ Ambient relative humidity """
1170
- TEMPERATURE: Optional[Data[tuple[StationName, Time], QuantityArray]] = None
1522
+ TEMPERATURE: Optional[
1523
+ Data[
1524
+ Union[
1525
+ tuple[StationName, Time],
1526
+ tuple[StationName, TimeWeather],
1527
+ ],
1528
+ QuantityInKelvinArray,
1529
+ ]
1530
+ ] = None
1171
1531
  """ Ambient air temperature for an antenna """
1172
- DEW_POINT: Optional[Data[tuple[StationName, Time], QuantityArray]] = None
1532
+ DEW_POINT: Optional[
1533
+ Data[
1534
+ Union[
1535
+ tuple[StationName, Time],
1536
+ tuple[StationName, TimeWeather],
1537
+ ],
1538
+ QuantityInKelvinArray,
1539
+ ]
1540
+ ] = None
1173
1541
  """ Dew point """
1174
- WIND_DIRECTION: Optional[Data[tuple[StationName, Time], QuantityArray]] = None
1542
+ WIND_DIRECTION: Optional[
1543
+ Data[
1544
+ Union[
1545
+ tuple[StationName, Time],
1546
+ tuple[StationName, TimeWeather],
1547
+ ],
1548
+ QuantityInRadiansArray,
1549
+ ]
1550
+ ] = None
1175
1551
  """ Average wind direction """
1176
- WIND_SPEED: Optional[Data[tuple[StationName, Time], QuantityArray]] = None
1552
+ WIND_SPEED: Optional[
1553
+ Data[
1554
+ Union[
1555
+ tuple[StationName, Time],
1556
+ tuple[StationName, TimeWeather],
1557
+ ],
1558
+ QuantityInMetersPerSecondArray,
1559
+ ]
1560
+ ] = None
1177
1561
  """ Average wind speed """
1178
- STATION_POSITION: Optional[Data[tuple[StationName], QuantityArray]] = None
1562
+ STATION_POSITION: Optional[Data[tuple[StationName], LocationArray]] = None
1179
1563
  """ Station position """
1180
1564
 
1181
1565
  # Attributes
1182
- type: Attr[str] = "weather"
1566
+ type: Attr[Literal["weather"]] = "weather"
1183
1567
  """
1184
1568
  Type of dataset.
1185
1569
  """
@@ -1187,6 +1571,40 @@ class WeatherXds:
1187
1571
 
1188
1572
  @xarray_dataset_schema
1189
1573
  class PointingXds:
1574
+ """
1575
+ Pointing dataset: antenna pointing information.
1576
+
1577
+ In the past the relationship and definition of the pointing infromation has not been clear. Here we attempt to clarify it by explaining the relationship between the ASDM, MSv2 and MSv4 pointing information.
1578
+
1579
+ The following abreviations are used:
1580
+
1581
+ - M2: Measurement Set version 2
1582
+ - M4: Measurement Set version 4
1583
+ - A : ASDM
1584
+
1585
+ The following definitions come from the ASDM's `SDM Tables Short Description <https://drive.google.com/file/d/16a3g0GQxgcO7N_ZabfdtexQ8r2jRbYIS/view>`_ page 97-99:
1586
+
1587
+ - A_encoder: The values measured from the antenna. They may be however affected by metrology, if applied. Note that for ALMA this column will contain positions obtained using the AZ POSN RSP and EL POSN RSP monitor points of the ACU and not the GET AZ ENC and GET EL ENC monitor points (as these do not include the metrology corrections). It is agreed that the the vendor pointing model will never be applied. AZELNOWAntenna.position
1588
+ - A_pointingDirection: This is the commanded direction of the antenna. It is obtained by adding the target and offset columns, and then applying the pointing model referenced by PointingModelId. The pointing model can be the composition of the absolute pointing model and of a local pointing model. In that case their coefficients will both be in the PointingModel table.
1589
+ - A_target: This is the field center direction (as given in the Field Table), possibly affected by the optional antenna-based sourceOffset. This column is in horizontal coordinates. AZELNOWAntenna.position
1590
+ - A_offset: Additional offsets in horizontal coordinates (usually meant for measuring the pointing corrections, mapping the antenna beam, ...). AZELNOWAntenna.positiontarget
1591
+ - A_sourceOffset : Optionally, the antenna-based mapping offsets in the field. These are in the equatorial system, and used, for instance, in on-the-fly mapping when the antennas are driven independently across the field.
1592
+
1593
+ M2_DIRECTION = rotate(A_target,A_offset) #A_target is rotated to by A_offset
1594
+
1595
+ if withPointingCorrection : M2_DIRECTION = rotate(A_target,A_offset) + (A_encoder - A_pointingDirection)
1596
+
1597
+ M2_TARGET = A_target
1598
+ M2_POINTING_OFFSET = A_offset
1599
+ M2_ENCODER = A_encoder
1600
+
1601
+ It should be noted that definition of M2_direction is not consistent, it depends if withPointingCorrection is set to True or False (see the `importasdm documenation <https://casadocs.readthedocs.io/en/v6.2.0/api/tt/casatasks.data.importasdm.html#with-pointing-correction>`_ and `code <https://open-bitbucket.nrao.edu/projects/CASA/repos/casa6/browse/casatools/src/tools/sdm/sdm_cmpt.cc#2257>`_ for details).
1602
+
1603
+ M4_DIRECTION = M2_DIRECTION (withPointingCorrection=True)
1604
+ M4_ENCODER = M2_ENCODER
1605
+
1606
+ """
1607
+
1190
1608
  antenna_name: Coordof[AntennaNameArray]
1191
1609
  """
1192
1610
  Antenna name, as specified by baseline_antenna1/2_name in visibility dataset
@@ -1207,10 +1625,10 @@ class PointingXds:
1207
1625
  LocalSkyCoordArray,
1208
1626
  ]
1209
1627
  """
1210
- Antenna pointing direction, optionally expressed as polynomial coefficients. DIRECTION in MSv3.
1628
+ The direction of the peak response of the beam and is equavalent to the MSv2 DIRECTION (M2_direction) with_pointing_correction=True, optionally expressed as polynomial coefficients.
1211
1629
  """
1212
1630
 
1213
- time: Optional[Coordof[TimeCoordArray]] = None
1631
+ time: Optional[Coordof[TimeInterpolatedCoordArray]] = None
1214
1632
  """
1215
1633
  Mid-point of the time interval for which the information in this row is
1216
1634
  valid. Required to use the same time measure reference as in visibility dataset.
@@ -1231,47 +1649,48 @@ class PointingXds:
1231
1649
  ] = None
1232
1650
  """
1233
1651
  The current encoder values on the primary axes of the mount type for
1234
- the antenna. ENCODER in MSv3.
1652
+ the antenna. ENCODER in MSv2 (M2_encoder).
1235
1653
  """
1236
1654
  POINTING_OVER_THE_TOP: Optional[
1237
1655
  Data[Union[tuple[Time, AntennaName], tuple[TimePointing, AntennaName]], bool]
1238
1656
  ] = None
1657
+ """
1658
+ True if the antenna was driven to this position ”over the top” (az-el mount).
1659
+ """
1239
1660
 
1240
-
1241
- @xarray_dataset_schema
1242
- class SpectralCoordXds:
1243
- # TODO
1244
- pass
1245
-
1246
-
1247
- @xarray_dataset_schema
1248
- class PhasedArrayXds:
1249
- # TODO
1250
- pass
1661
+ # Attributes
1662
+ type: Attr[Literal["pointing"]] = "pointing"
1663
+ """
1664
+ Type of dataset.
1665
+ """
1251
1666
 
1252
1667
 
1253
1668
  @xarray_dataset_schema
1254
1669
  class SystemCalibrationXds:
1255
- """System calibration. Contains time- and frequency- variable
1256
- calibration measurements for each antenna, as indexed on receptor"""
1670
+ """
1671
+ System calibration dataset: time- and frequency- variable calibration measurements for each antenna,
1672
+ as indexed on receptor
1673
+ """
1257
1674
 
1258
1675
  # Coordinates
1259
1676
  antenna_name: Coordof[AntennaNameArray]
1260
1677
  """ Antenna identifier """
1261
1678
  receptor_label: Coord[ReceptorLabel, numpy.int64]
1262
1679
  """ """
1263
- time: Optional[Coordof[TimeCoordArray]] = None
1680
+ time: Optional[Coordof[TimeInterpolatedCoordArray]] = None
1264
1681
  """ Midpoint of time for which this set of parameters is accurate. Labeled 'time' when interpolating to main time axis """
1265
1682
  time_cal: Optional[Coordof[TimeCalCoordArray]] = None
1266
1683
  """ Midpoint of time for which this set of parameters is accurate. Labeled 'time_cal' when not interpolating to main time axis """
1267
- # frequency: Optional[Coordof[FrequencyArray]] = None
1268
1684
  frequency: Optional[Coordof[FrequencyCalArray]] = None
1269
1685
  """ """
1686
+ frequency_cal: Optional[Coord[FrequencyCal, int]] = None
1687
+ """TODO: What is this?"""
1270
1688
 
1271
1689
  # Data variables (all optional)
1272
1690
  PHASE_DIFFERENCE: Optional[
1273
1691
  Data[
1274
- Union[tuple[AntennaName, TimeCal], tuple[AntennaName, Time]], numpy.float64
1692
+ Union[tuple[AntennaName, TimeCal], tuple[AntennaName, Time]],
1693
+ QuantityInRadiansArray,
1275
1694
  ]
1276
1695
  ] = None
1277
1696
  """ Phase difference between receptor 0 and receptor 1 """
@@ -1285,7 +1704,7 @@ class SystemCalibrationXds:
1285
1704
  tuple[AntennaName, Time, ReceptorLabel, Frequency],
1286
1705
  tuple[AntennaName, Time, ReceptorLabel],
1287
1706
  ],
1288
- QuantityArray,
1707
+ QuantityInKelvinArray,
1289
1708
  ]
1290
1709
  ] = None
1291
1710
  """ Calibration temp """
@@ -1299,7 +1718,7 @@ class SystemCalibrationXds:
1299
1718
  tuple[AntennaName, Time, ReceptorLabel, Frequency],
1300
1719
  tuple[AntennaName, Time, ReceptorLabel],
1301
1720
  ],
1302
- QuantityArray,
1721
+ QuantityInKelvinArray,
1303
1722
  ]
1304
1723
  ] = None
1305
1724
  """ Receiver temperature """
@@ -1313,7 +1732,7 @@ class SystemCalibrationXds:
1313
1732
  tuple[AntennaName, Time, ReceptorLabel, Frequency],
1314
1733
  tuple[AntennaName, Time, ReceptorLabel],
1315
1734
  ],
1316
- QuantityArray,
1735
+ QuantityInKelvinArray,
1317
1736
  ]
1318
1737
  ] = None
1319
1738
  """ Sky temperature """
@@ -1327,7 +1746,7 @@ class SystemCalibrationXds:
1327
1746
  tuple[AntennaName, Time, ReceptorLabel, Frequency],
1328
1747
  tuple[AntennaName, Time, ReceptorLabel],
1329
1748
  ],
1330
- QuantityArray,
1749
+ QuantityInKelvinArray,
1331
1750
  ]
1332
1751
  ] = None
1333
1752
  """ System temperature """
@@ -1341,7 +1760,7 @@ class SystemCalibrationXds:
1341
1760
  tuple[AntennaName, Time, ReceptorLabel, Frequency],
1342
1761
  tuple[AntennaName, Time, ReceptorLabel],
1343
1762
  ],
1344
- QuantityArray,
1763
+ QuantityInKelvinArray,
1345
1764
  ]
1346
1765
  ] = None
1347
1766
  """ Antenna temperature """
@@ -1355,21 +1774,35 @@ class SystemCalibrationXds:
1355
1774
  tuple[AntennaName, Time, ReceptorLabel, Frequency],
1356
1775
  tuple[AntennaName, Time, ReceptorLabel],
1357
1776
  ],
1358
- QuantityArray,
1777
+ QuantityInKelvinArray,
1359
1778
  ]
1360
1779
  ] = None
1361
1780
  """ TANT/TSYS """
1362
1781
 
1363
1782
  # Attributes
1364
- type: Attr[str] = "system_calibration"
1783
+ type: Attr[Literal["system_calibration"]] = "system_calibration"
1365
1784
  """
1366
1785
  Type of dataset.
1367
1786
  """
1368
1787
 
1369
1788
 
1789
+ @xarray_dataset_schema
1790
+ class PhasedArrayXds:
1791
+ """Not specified. Not implemented."""
1792
+
1793
+ pass
1794
+
1795
+
1796
+ @xarray_dataset_schema
1797
+ class DopplerXds:
1798
+ """Not specified. Not implemented."""
1799
+
1800
+ pass
1801
+
1802
+
1370
1803
  @xarray_dataset_schema
1371
1804
  class VisibilityXds:
1372
- """TODO: documentation"""
1805
+ """Main dataset for interferometric data"""
1373
1806
 
1374
1807
  # --- Required Coordinates ---
1375
1808
  time: Coordof[TimeCoordArray]
@@ -1377,27 +1810,23 @@ class VisibilityXds:
1377
1810
  The time coordinate is the mid-point of the nominal sampling interval, as
1378
1811
  specified in the ``ms_v4.time.attrs['integration_time']`` (ms v2 interval).
1379
1812
  """
1380
- baseline_id: Optional[Coordof[BaselineArray]] # IF. not present in main_sd_xds
1813
+ baseline_id: Coordof[BaselineArray]
1381
1814
  """ Baseline ID """
1382
- antenna_name: Optional[
1383
- Coordof[AntennaNameArray]
1384
- ] # Single-dish. not present in main_xds
1385
- """ antenna_name """
1386
1815
  frequency: Coordof[FrequencyArray]
1387
1816
  """Center frequencies for each channel."""
1388
1817
  polarization: Coordof[PolarizationArray]
1389
1818
  """
1390
1819
  Labels for polarization types, e.g. ``['XX','XY','YX','YY']``, ``['RR','RL','LR','LL']``.
1391
1820
  """
1392
- polarization_mixed: Optional[Coord[tuple[BaselineId, Polarization], str]]
1393
- """
1394
- If the polarizations are not constant over baseline
1395
- """
1396
- uvw_label: Optional[Coordof[UvwLabelArray]]
1397
- """ u,v,w """
1398
- baseline_antenna1_name: Optional[Coordof[BaselineAntennaNameArray]] # IF
1821
+
1822
+ # --- Required data variables ---
1823
+
1824
+ VISIBILITY: Dataof[VisibilityArray]
1825
+ """Complex visibilities, either simulated or measured by interferometer."""
1826
+
1827
+ baseline_antenna1_name: Coordof[BaselineAntennaNameArray]
1399
1828
  """Antenna name for 1st antenna in baseline. Maps to ``attrs['antenna_xds'].antenna_name``"""
1400
- baseline_antenna2_name: Optional[Coordof[BaselineAntennaNameArray]] # IF
1829
+ baseline_antenna2_name: Coordof[BaselineAntennaNameArray]
1401
1830
  """Antenna name for 2nd antenna in baseline. Maps to ``attrs['antenna_xds'].antenna_name``"""
1402
1831
 
1403
1832
  # --- Required Attributes ---
@@ -1406,43 +1835,42 @@ class VisibilityXds:
1406
1835
  processor_info: Attr[ProcessorInfoDict]
1407
1836
  antenna_xds: Attr[AntennaXds]
1408
1837
 
1409
- schema_version: Attr[str] = None
1838
+ schema_version: Attr[str]
1410
1839
  """Semantic version of xradio data format"""
1411
- creation_date: Attr[str] = None
1840
+ creation_date: Attr[str]
1412
1841
  """Date visibility dataset was created . Format: YYYY-MM-DDTHH:mm:ss.SSS (ISO 8601)"""
1413
1842
 
1843
+ type: Attr[Literal["visibility"]] = "visibility"
1844
+ """
1845
+ Dataset type
1846
+ """
1847
+
1414
1848
  # --- Optional Coordinates ---
1849
+ polarization_mixed: Optional[Coord[tuple[BaselineId, Polarization], str]] = None
1850
+ """
1851
+ If the polarizations are not constant over baseline
1852
+ """
1853
+ uvw_label: Optional[Coordof[UvwLabelArray]] = None
1854
+ """ u,v,w """
1415
1855
  scan_number: Optional[Coord[Time, Union[numpy.int64, numpy.int32]]] = None
1416
1856
  """Arbitary scan number to identify data taken in the same logical scan."""
1417
1857
 
1418
- # --- Required data variables ---
1419
-
1420
1858
  # --- Optional data variables / arrays ---
1421
1859
 
1422
- # Either VISIBILITY (interferometry) or SPECTRUM (single-dish)
1423
- VISIBILITY: Optional[Dataof[VisibilityArray]] = None
1424
- """Complex visibilities, either simulated or measured by interferometer."""
1425
- SPECTRUM: Optional[Dataof[SpectrumArray]] = None
1426
- """Single dish data, either simulated or measured by an antenna."""
1427
-
1428
- VISIBILITY_CORRECTED: Optional[Dataof[VisibilityArray]] = None
1429
- VISIBILITY_MODEL: Optional[Dataof[VisibilityArray]] = None
1430
- SPECTRUM_CORRECTED: Optional[Dataof[SpectrumArray]] = None
1860
+ # VISIBILITY_CORRECTED: Optional[Dataof[VisibilityArray]] = None
1861
+ # VISIBILITY_MODEL: Optional[Dataof[VisibilityArray]] = None
1431
1862
 
1432
- FLAG: Optional[Dataof[FlagArray]] = None
1433
- WEIGHT: Optional[Dataof[WeightArray]] = None
1434
- UVW: Optional[Dataof[UvwArray]] = None
1863
+ FLAG: Dataof[FlagArray] = None
1864
+ WEIGHT: Dataof[WeightArray] = None
1865
+ UVW: Dataof[UvwArray] = None
1435
1866
  EFFECTIVE_INTEGRATION_TIME: Optional[
1436
1867
  Data[
1437
1868
  Union[
1438
1869
  tuple[Time, BaselineId],
1439
1870
  tuple[Time, BaselineId, Frequency],
1440
1871
  tuple[Time, BaselineId, Frequency, Polarization],
1441
- tuple[Time, AntennaName], # SD
1442
- tuple[Time, AntennaName, Frequency], # SD
1443
- tuple[Time, AntennaName, Frequency, Polarization], # SD
1444
1872
  ],
1445
- QuantityArray,
1873
+ QuantityInSecondsArray,
1446
1874
  ]
1447
1875
  ] = None
1448
1876
  """
@@ -1482,7 +1910,103 @@ class VisibilityXds:
1482
1910
  The id assigned to this combination of spectral window and polarization setup.
1483
1911
  """
1484
1912
 
1485
- type: Attr[str] = "visibility"
1913
+
1914
+ @xarray_dataset_schema
1915
+ class SpectrumXds:
1916
+ """Main dataset for single dish data"""
1917
+
1918
+ # --- Required Coordinates ---
1919
+ time: Coordof[TimeCoordArray]
1920
+ """
1921
+ The time coordinate is the mid-point of the nominal sampling interval, as
1922
+ specified in the ``ms_v4.time.attrs['integration_time']`` (ms v2 interval).
1923
+ """
1924
+ antenna_name: Coordof[AntennaNameArray]
1925
+ """ antenna_name """
1926
+ frequency: Coordof[FrequencyArray]
1927
+ """Center frequencies for each channel."""
1928
+ polarization: Coordof[PolarizationArray]
1929
+ """
1930
+ Labels for polarization types, e.g. ``['XX','XY','YX','YY']``, ``['RR','RL','LR','LL']``.
1931
+ """
1932
+
1933
+ # --- Required data variables ---
1934
+ SPECTRUM: Dataof[SpectrumArray]
1935
+ """Single dish data, either simulated or measured by an antenna."""
1936
+
1937
+ # --- Required Attributes ---
1938
+ partition_info: Attr[PartitionInfoDict]
1939
+ observation_info: Attr[ObservationInfoDict]
1940
+ processor_info: Attr[ProcessorInfoDict]
1941
+ antenna_xds: Attr[AntennaXds]
1942
+
1943
+ schema_version: Attr[str]
1944
+ """Semantic version of xradio data format"""
1945
+ creation_date: Attr[str]
1946
+ """Date MSv4 was created . Format: YYYY-MM-DDTHH:mm:ss.SSS (ISO 8601)"""
1947
+
1948
+ type: Attr[Literal["spectrum"]] = "spectrum"
1486
1949
  """
1487
1950
  Dataset type
1488
1951
  """
1952
+
1953
+ # --- Optional Coordinates ---
1954
+ polarization_mixed: Optional[Coord[tuple[AntennaName, Polarization], str]] = None
1955
+ """
1956
+ If the polarizations are not constant over baseline
1957
+ """
1958
+ scan_number: Optional[Coord[Time, Union[numpy.int64, numpy.int32]]] = None
1959
+ """Arbitary scan number to identify data taken in the same logical scan."""
1960
+
1961
+ # SPECTRUM_CORRECTED: Optional[Dataof[SpectrumArray]] = None
1962
+
1963
+ FLAG: Dataof[FlagArray] = None
1964
+ WEIGHT: Dataof[WeightArray] = None
1965
+
1966
+ # --- Optional data variables / arrays ---
1967
+ EFFECTIVE_INTEGRATION_TIME: Optional[
1968
+ Data[
1969
+ Union[
1970
+ tuple[Time, AntennaName],
1971
+ tuple[Time, AntennaName, Frequency],
1972
+ tuple[Time, AntennaName, Frequency, Polarization],
1973
+ ],
1974
+ QuantityInSecondsArray,
1975
+ ]
1976
+ ] = None
1977
+ """
1978
+ The integration time, including the effects of missing data, in contrast to
1979
+ ``integration_time`` attribute of the ``time`` coordinate,
1980
+ see :py:class:`TimeArray`. (MS v2: ``exposure``).
1981
+ """
1982
+ TIME_CENTROID: Optional[Dataof[TimeSamplingArray]] = None
1983
+ """
1984
+ The time centroid of the visibility, includes the effects of missing data
1985
+ unlike the ``time`` coordinate, see :py:class:`TimeArray`.
1986
+ """
1987
+ TIME_CENTROID_EXTRA_PRECISION: Optional[Dataof[TimeSamplingArray]] = None
1988
+ """Additional precision for ``TIME_CENTROID``"""
1989
+ EFFECTIVE_CHANNEL_WIDTH: Optional[Dataof[FreqSamplingArray]] = None
1990
+ """The channel bandwidth that includes the effects of missing data."""
1991
+ FREQUENCY_CENTROID: Optional[Dataof[FreqSamplingArray]] = None
1992
+ """Includes the effects of missing data unlike ``frequency``."""
1993
+
1994
+ # --- Optional Attributes ---
1995
+ pointing_xds: Optional[Attr[PointingXds]] = None
1996
+ system_calibration_xds: Optional[Attr[SystemCalibrationXds]] = None
1997
+ gain_curve_xds: Optional[Attr[GainCurveXds]] = None
1998
+ phase_calibration_xds: Optional[Attr[PhaseCalibrationXds]] = None
1999
+ weather_xds: Optional[Attr[WeatherXds]] = None
2000
+ phased_array_xds: Optional[Attr[PhasedArrayXds]] = None
2001
+
2002
+ xradio_version: Optional[Attr[str]] = None
2003
+ """ Version of XRADIO used if converted from MSv2. """
2004
+
2005
+ intent: Optional[Attr[str]] = None
2006
+ """Identifies the intention of the scan, such as to calibrate or observe a
2007
+ target. See :ref:`scan intents` for possible values.
2008
+ """
2009
+ data_description_id: Optional[Attr[str]] = None
2010
+ """
2011
+ The id assigned to this combination of spectral window and polarization setup.
2012
+ """