xradio 0.0.48__py3-none-any.whl → 0.0.49__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.
- xradio/__init__.py +1 -0
- xradio/_utils/dict_helpers.py +69 -2
- xradio/image/_util/__init__.py +0 -3
- xradio/image/_util/_casacore/common.py +0 -13
- xradio/image/_util/_casacore/xds_from_casacore.py +102 -97
- xradio/image/_util/_casacore/xds_to_casacore.py +36 -24
- xradio/image/_util/_fits/xds_from_fits.py +81 -36
- xradio/image/_util/_zarr/zarr_low_level.py +3 -3
- xradio/image/_util/casacore.py +7 -5
- xradio/image/_util/common.py +13 -26
- xradio/image/_util/image_factory.py +143 -191
- xradio/image/image.py +10 -59
- xradio/measurement_set/__init__.py +11 -6
- xradio/measurement_set/_utils/_msv2/_tables/read.py +187 -46
- xradio/measurement_set/_utils/_msv2/_tables/table_query.py +22 -0
- xradio/measurement_set/_utils/_msv2/conversion.py +351 -318
- xradio/measurement_set/_utils/_msv2/msv4_info_dicts.py +20 -17
- xradio/measurement_set/convert_msv2_to_processing_set.py +46 -6
- xradio/measurement_set/load_processing_set.py +100 -53
- xradio/measurement_set/measurement_set_xdt.py +197 -0
- xradio/measurement_set/open_processing_set.py +122 -86
- xradio/measurement_set/processing_set_xdt.py +1552 -0
- xradio/measurement_set/schema.py +199 -94
- xradio/schema/bases.py +5 -1
- xradio/schema/check.py +97 -5
- {xradio-0.0.48.dist-info → xradio-0.0.49.dist-info}/METADATA +4 -4
- {xradio-0.0.48.dist-info → xradio-0.0.49.dist-info}/RECORD +30 -30
- {xradio-0.0.48.dist-info → xradio-0.0.49.dist-info}/WHEEL +1 -1
- xradio/measurement_set/measurement_set_xds.py +0 -117
- xradio/measurement_set/processing_set.py +0 -803
- {xradio-0.0.48.dist-info → xradio-0.0.49.dist-info/licenses}/LICENSE.txt +0 -0
- {xradio-0.0.48.dist-info → xradio-0.0.49.dist-info}/top_level.txt +0 -0
xradio/measurement_set/schema.py
CHANGED
|
@@ -9,6 +9,8 @@ from xradio.schema.bases import (
|
|
|
9
9
|
from xradio.schema.typing import Attr, Coord, Coordof, Data, Dataof, Name
|
|
10
10
|
import numpy
|
|
11
11
|
|
|
12
|
+
MSV4_SCHEMA_VERSION = "4.0.-9988"
|
|
13
|
+
|
|
12
14
|
# Dimensions
|
|
13
15
|
Time = Literal["time"]
|
|
14
16
|
""" Observation time dimension """
|
|
@@ -670,7 +672,7 @@ class DopplerArray:
|
|
|
670
672
|
data: Data[ZD, numpy.float64]
|
|
671
673
|
|
|
672
674
|
type: Attr[Doppler] = "doppler"
|
|
673
|
-
""" Coordinate type. Should be ``"
|
|
675
|
+
""" Coordinate type. Should be ``"doppler"``. """
|
|
674
676
|
|
|
675
677
|
units: Attr[UnitsOfDopplerShift] = ("m/s",)
|
|
676
678
|
""" Units to associate with axis, [ratio]/[m/s]"""
|
|
@@ -788,11 +790,18 @@ class FlagArray:
|
|
|
788
790
|
flagged bad if the ``FLAG`` array element is ``True``.
|
|
789
791
|
"""
|
|
790
792
|
|
|
793
|
+
# data: Data[
|
|
794
|
+
# Union[
|
|
795
|
+
# tuple[Time, BaselineId, Frequency, Polarization],
|
|
796
|
+
# tuple[Time, BaselineId, Frequency],
|
|
797
|
+
# tuple[Time, BaselineId],
|
|
798
|
+
# tuple[Time, AntennaName, Frequency, Polarization], # SD
|
|
799
|
+
# ],
|
|
800
|
+
# bool,
|
|
801
|
+
# ]
|
|
791
802
|
data: Data[
|
|
792
803
|
Union[
|
|
793
804
|
tuple[Time, BaselineId, Frequency, Polarization],
|
|
794
|
-
tuple[Time, BaselineId, Frequency],
|
|
795
|
-
tuple[Time, BaselineId],
|
|
796
805
|
tuple[Time, AntennaName, Frequency, Polarization], # SD
|
|
797
806
|
],
|
|
798
807
|
bool,
|
|
@@ -820,12 +829,20 @@ class WeightArray:
|
|
|
820
829
|
data: Data[
|
|
821
830
|
Union[
|
|
822
831
|
tuple[Time, BaselineId, Frequency, Polarization],
|
|
823
|
-
tuple[Time, BaselineId, Frequency],
|
|
824
|
-
tuple[Time, BaselineId],
|
|
825
832
|
tuple[Time, AntennaName, Frequency, Polarization], # SD
|
|
826
833
|
],
|
|
827
834
|
Union[numpy.float16, numpy.float32, numpy.float64],
|
|
828
835
|
]
|
|
836
|
+
|
|
837
|
+
# data: Data[
|
|
838
|
+
# Union[
|
|
839
|
+
# tuple[Time, BaselineId, Frequency, Polarization],
|
|
840
|
+
# tuple[Time, BaselineId, Frequency],
|
|
841
|
+
# tuple[Time, BaselineId],
|
|
842
|
+
# tuple[Time, AntennaName, Frequency, Polarization], # SD
|
|
843
|
+
# ],
|
|
844
|
+
# Union[numpy.float16, numpy.float32, numpy.float64],
|
|
845
|
+
# ]
|
|
829
846
|
"""Visibility weights"""
|
|
830
847
|
time: Coordof[TimeCoordArray]
|
|
831
848
|
baseline_id: Optional[Coordof[BaselineArray]] # Only IF
|
|
@@ -928,19 +945,79 @@ class TimeSamplingArray:
|
|
|
928
945
|
units: Attr[UnitsSeconds] = ("s",)
|
|
929
946
|
|
|
930
947
|
|
|
948
|
+
# @xarray_dataarray_schema
|
|
949
|
+
# class FreqSamplingArray:
|
|
950
|
+
# """
|
|
951
|
+
# Model of frequency related data variables of the main dataset, such as EFFECTIV_CHANNEL_WIDTH and FREQUENCY_CENTROID.
|
|
952
|
+
# """
|
|
953
|
+
|
|
954
|
+
# data: Data[
|
|
955
|
+
# Union[
|
|
956
|
+
# tuple[Time, BaselineId, Frequency, Polarization],
|
|
957
|
+
# tuple[Time, BaselineId, Frequency],
|
|
958
|
+
# tuple[Time, Frequency],
|
|
959
|
+
# tuple[Frequency],
|
|
960
|
+
# ],
|
|
961
|
+
# float,
|
|
962
|
+
# ]
|
|
963
|
+
# """
|
|
964
|
+
# Data about frequency sampling, such as centroid or integration
|
|
965
|
+
# time. Concrete function depends on concrete data array within
|
|
966
|
+
# :py:class:`VisibilityXds` or :py:class:`SpectrumXds`.
|
|
967
|
+
# """
|
|
968
|
+
# frequency: Coordof[FrequencyArray]
|
|
969
|
+
# time: Optional[Coordof[TimeCoordArray]] = None
|
|
970
|
+
# baseline_id: Optional[Coordof[BaselineArray]] = None
|
|
971
|
+
# polarization: Optional[Coordof[PolarizationArray]] = None
|
|
972
|
+
# long_name: Optional[Attr[str]] = "Frequency sampling data"
|
|
973
|
+
# units: Attr[UnitsHertz] = ("Hz",)
|
|
974
|
+
# observer: Attr[AllowedSpectralCoordFrames] = "icrs"
|
|
975
|
+
# """
|
|
976
|
+
# Astropy velocity reference frames (see :external:ref:`astropy-spectralcoord`).
|
|
977
|
+
# Note that Astropy does not use the name
|
|
978
|
+
# 'topo' (telescope centric) velocity frame, rather it assumes if no velocity
|
|
979
|
+
# frame is given that this is the default.
|
|
980
|
+
# """
|
|
981
|
+
|
|
982
|
+
|
|
983
|
+
@xarray_dataarray_schema
|
|
984
|
+
class FrequencyCentroidArray:
|
|
985
|
+
"""
|
|
986
|
+
Model of frequency related data variables of the main dataset, such as FREQUENCY_CENTROID.
|
|
987
|
+
"""
|
|
988
|
+
|
|
989
|
+
data: Data[
|
|
990
|
+
tuple[Frequency],
|
|
991
|
+
float,
|
|
992
|
+
]
|
|
993
|
+
"""
|
|
994
|
+
Data about frequency sampling, such as centroid or integration
|
|
995
|
+
time. Concrete function depends on concrete data array within
|
|
996
|
+
:py:class:`VisibilityXds` or :py:class:`SpectrumXds`.
|
|
997
|
+
"""
|
|
998
|
+
frequency: Coordof[FrequencyArray]
|
|
999
|
+
long_name: Optional[Attr[str]] = "Frequency sampling data"
|
|
1000
|
+
units: Attr[UnitsHertz] = ("Hz",)
|
|
1001
|
+
observer: Attr[AllowedSpectralCoordFrames] = "icrs"
|
|
1002
|
+
"""
|
|
1003
|
+
Astropy velocity reference frames (see :external:ref:`astropy-spectralcoord`).
|
|
1004
|
+
Note that Astropy does not use the name
|
|
1005
|
+
'topo' (telescope centric) velocity frame, rather it assumes if no velocity
|
|
1006
|
+
frame is given that this is the default.
|
|
1007
|
+
"""
|
|
1008
|
+
|
|
1009
|
+
|
|
931
1010
|
@xarray_dataarray_schema
|
|
932
|
-
class
|
|
1011
|
+
class EffectiveChannelWidthArray:
|
|
933
1012
|
"""
|
|
934
|
-
Model of frequency related data variables of the main dataset, such as EFFECTIV_CHANNEL_WIDTH
|
|
1013
|
+
Model of frequency related data variables of the main dataset, such as EFFECTIV_CHANNEL_WIDTH.
|
|
935
1014
|
"""
|
|
936
1015
|
|
|
937
1016
|
data: Data[
|
|
938
1017
|
Union[
|
|
939
1018
|
tuple[Time, BaselineId, Frequency, Polarization],
|
|
940
|
-
tuple[Time,
|
|
941
|
-
|
|
942
|
-
tuple[Frequency],
|
|
943
|
-
],
|
|
1019
|
+
tuple[Time, AntennaName, Frequency, Polarization],
|
|
1020
|
+
], # SD
|
|
944
1021
|
float,
|
|
945
1022
|
]
|
|
946
1023
|
"""
|
|
@@ -963,7 +1040,7 @@ class FreqSamplingArray:
|
|
|
963
1040
|
"""
|
|
964
1041
|
|
|
965
1042
|
|
|
966
|
-
# Define
|
|
1043
|
+
# Define FieldSourceXds and FieldSourceEphemerisXds already here, as they are needed in the
|
|
967
1044
|
# definition of VisibilityArray
|
|
968
1045
|
@xarray_dataset_schema
|
|
969
1046
|
class FieldSourceXds:
|
|
@@ -1222,9 +1299,6 @@ class SpectrumArray:
|
|
|
1222
1299
|
frequency: Coordof[FrequencyArray]
|
|
1223
1300
|
polarization: Coordof[PolarizationArray]
|
|
1224
1301
|
|
|
1225
|
-
field_and_source_xds: Attr[Union[FieldSourceXds, FieldSourceEphemerisXds]]
|
|
1226
|
-
""" Field and source information. Also alows for variant where ephemeris information is included. """
|
|
1227
|
-
|
|
1228
1302
|
long_name: Optional[Attr[str]] = "Spectrum values"
|
|
1229
1303
|
""" Long-form name to use for axis. Should be ``"Spectrum values"``"""
|
|
1230
1304
|
units: Attr[list[str]] = ("Jy",)
|
|
@@ -1244,9 +1318,6 @@ class VisibilityArray:
|
|
|
1244
1318
|
polarization: Coordof[PolarizationArray]
|
|
1245
1319
|
frequency: Coordof[FrequencyArray]
|
|
1246
1320
|
|
|
1247
|
-
field_and_source_xds: Attr[Union[FieldSourceXds, FieldSourceEphemerisXds]]
|
|
1248
|
-
""" Field and source information. Also alows for variant where ephemeris information is included. """
|
|
1249
|
-
|
|
1250
1321
|
long_name: Optional[Attr[str]] = "Visibility values"
|
|
1251
1322
|
""" Long-form name to use for axis. Should be ``"Visibility values"``"""
|
|
1252
1323
|
units: Attr[list[str]] = ("Jy",)
|
|
@@ -1257,32 +1328,32 @@ class VisibilityArray:
|
|
|
1257
1328
|
# Info dicts
|
|
1258
1329
|
|
|
1259
1330
|
|
|
1260
|
-
@dict_schema
|
|
1261
|
-
class PartitionInfoDict:
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1331
|
+
# @dict_schema
|
|
1332
|
+
# class PartitionInfoDict:
|
|
1333
|
+
# # spectral_window_id: missing / remove for good?
|
|
1334
|
+
# spectral_window_name: str
|
|
1335
|
+
# """ Spectral window Name """
|
|
1336
|
+
# # field_id: missing / probably remove for good?
|
|
1337
|
+
# field_name: list[str]
|
|
1338
|
+
# """ List of all field names """
|
|
1339
|
+
# polarization_setup: list[str]
|
|
1340
|
+
# """ List of polrization bases. """
|
|
1341
|
+
# scan_name: list[str]
|
|
1342
|
+
# """ List of scan names. """
|
|
1343
|
+
# source_name: list[str]
|
|
1344
|
+
# """ List of source names. """
|
|
1345
|
+
# # source_id: mising / remove for good?
|
|
1346
|
+
# intents: list[str]
|
|
1347
|
+
# """ An intent string identifies one intention of the scan, such as to calibrate or observe a
|
|
1348
|
+
# target. See :ref:`scan intents` for possible values. When converting from MSv2, the list of
|
|
1349
|
+
# intents is derived from the OBS_MODE column of MSv2 state table (every comma separated value
|
|
1350
|
+
# is taken as an intent). """
|
|
1351
|
+
# taql: Optional[str]
|
|
1352
|
+
# """ The taql query used if converted from MSv2. """
|
|
1353
|
+
# line_name: list[str]
|
|
1354
|
+
# """ Spectral line names """
|
|
1355
|
+
# antenna_name: Optional[str]
|
|
1356
|
+
# """ Name of antenna when partitioning also by antenna (single-dish). """
|
|
1286
1357
|
|
|
1287
1358
|
|
|
1288
1359
|
@dict_schema
|
|
@@ -1310,6 +1381,11 @@ class ObservationInfoDict:
|
|
|
1310
1381
|
"""ASDM: A reference to the Entity which contains the observing script."""
|
|
1311
1382
|
observing_log: Optional[str]
|
|
1312
1383
|
"""ASDM: Logs of the observation during this execu- tion block."""
|
|
1384
|
+
intents: list[str]
|
|
1385
|
+
""" An intent string identifies one intention of the scan, such as to calibrate or observe a
|
|
1386
|
+
target. See :ref:`scan intents` for possible values. When converting from MSv2, the list of
|
|
1387
|
+
intents is derived from the OBS_MODE column of MSv2 state table (every comma separated value
|
|
1388
|
+
is taken as an intent). """
|
|
1313
1389
|
|
|
1314
1390
|
|
|
1315
1391
|
@dict_schema
|
|
@@ -1322,6 +1398,39 @@ class ProcessorInfoDict:
|
|
|
1322
1398
|
"""Processor sub-type, e.g. ”GBT” or ”JIVE”."""
|
|
1323
1399
|
|
|
1324
1400
|
|
|
1401
|
+
@dict_schema
|
|
1402
|
+
class DataGroupDict:
|
|
1403
|
+
"""Defines a group of correlated data + flag + weight + uvw variables."""
|
|
1404
|
+
|
|
1405
|
+
correlated_data: str
|
|
1406
|
+
""" Name of the correlated data variable, for example 'VISIBILITY' or 'VISIBILITY_MODEL'. """
|
|
1407
|
+
flag: str
|
|
1408
|
+
""" Name of the flag variable, for example 'FLAG'. """
|
|
1409
|
+
weight: str
|
|
1410
|
+
""" Name of the weight variable of the group, for example 'WEIGHT'. """
|
|
1411
|
+
uvw: Optional[str]
|
|
1412
|
+
""" Name of the UVW variable of the group, for example 'UVW'. """
|
|
1413
|
+
description: str
|
|
1414
|
+
""" More details about the data group. """
|
|
1415
|
+
date: str
|
|
1416
|
+
""" Creation date-time, in ISO 8601 format: 'YYYY-MM-DDTHH:mm:ss.SSS'. """
|
|
1417
|
+
|
|
1418
|
+
|
|
1419
|
+
@dict_schema
|
|
1420
|
+
class DataGroupsDict:
|
|
1421
|
+
"""Dictionary of data group dictionaries."""
|
|
1422
|
+
|
|
1423
|
+
base: DataGroupDict
|
|
1424
|
+
|
|
1425
|
+
|
|
1426
|
+
@dict_schema
|
|
1427
|
+
class CreatorDict:
|
|
1428
|
+
software_name: str
|
|
1429
|
+
""" Software that created the Measurement Set (XRadio, etc.). """
|
|
1430
|
+
version: str
|
|
1431
|
+
""" Version of the software. """
|
|
1432
|
+
|
|
1433
|
+
|
|
1325
1434
|
# Data Sets
|
|
1326
1435
|
|
|
1327
1436
|
|
|
@@ -1338,11 +1447,13 @@ class AntennaXds:
|
|
|
1338
1447
|
""" Name of the station pad (relevant to arrays with moving antennas). """
|
|
1339
1448
|
mount: Coord[AntennaName, str]
|
|
1340
1449
|
""" Mount type of the antenna. Reserved keywords include: ”EQUATORIAL” - equatorial mount;
|
|
1341
|
-
”ALT-AZ
|
|
1342
|
-
"ALT-AZ+ROTATOR"
|
|
1450
|
+
”ALT-AZ”: azimuth-elevation mount;
|
|
1451
|
+
"ALT-AZ+ROTATOR": alt-az mount with feed rotator; introduced for ASKAP dishes;
|
|
1343
1452
|
"ALT-AZ+NASMYTH-R": Nasmyth mount with receivers at the right-hand side of the cabin. Many high-frequency antennas used for VLBI have such a mount typel;
|
|
1344
|
-
"ALT-AZ+NASMYTH-L
|
|
1345
|
-
|
|
1453
|
+
"ALT-AZ+NASMYTH-L": Nasmyth mount with receivers at the left-hand side of the cabin.
|
|
1454
|
+
"ALT-AZ+BWG-R": alt-az mount that uses a Beam Wave Guide to bring the focus down to the pedestal. The receivers are at the right-hand side of the cabin (-R). Compared to the Nasmyth mounts there is an extra correction term because there are now two rotating mirrors. See https://arxiv.org/abs/2210.13381 for more details.
|
|
1455
|
+
"ALT-AZ+BWG-L": alt-az mount that uses a Beam Wave Guide, as above, but with receivers at the left-hand side of the cabin.
|
|
1456
|
+
”X-Y”: x-y mount;
|
|
1346
1457
|
”SPACE-HALCA” - specific orientation model."""
|
|
1347
1458
|
telescope_name: Coord[AntennaName, str]
|
|
1348
1459
|
""" Useful when data is combined from mutiple arrays for example ACA + ALMA. """
|
|
@@ -1420,11 +1531,13 @@ class GainCurveXds:
|
|
|
1420
1531
|
""" Name of the station pad (relevant to arrays with moving antennas). """
|
|
1421
1532
|
mount: Coord[AntennaName, str]
|
|
1422
1533
|
""" Mount type of the antenna. Reserved keywords include: ”EQUATORIAL” - equatorial mount;
|
|
1423
|
-
”ALT-AZ
|
|
1424
|
-
"ALT-AZ+ROTATOR"
|
|
1534
|
+
”ALT-AZ”: azimuth-elevation mount;
|
|
1535
|
+
"ALT-AZ+ROTATOR": alt-az mount with feed rotator; introduced for ASKAP dishes;
|
|
1425
1536
|
"ALT-AZ+NASMYTH-R": Nasmyth mount with receivers at the right-hand side of the cabin. Many high-frequency antennas used for VLBI have such a mount typel;
|
|
1426
|
-
"ALT-AZ+NASMYTH-L
|
|
1427
|
-
|
|
1537
|
+
"ALT-AZ+NASMYTH-L": Nasmyth mount with receivers at the left-hand side of the cabin.
|
|
1538
|
+
"ALT-AZ+BWG-R": alt-az mount that uses a Beam Wave Guide to bring the focus down to the pedestal. The receivers are at the right-hand side of the cabin (-R). Compared to the Nasmyth mounts there is an extra correction term because there are now two rotating mirrors. See https://arxiv.org/abs/2210.13381 for more details.
|
|
1539
|
+
"ALT-AZ+BWG-L": alt-az mount that uses a Beam Wave Guide, as above, but with receivers at the left-hand side of the cabin.
|
|
1540
|
+
”X-Y”: x-y mount;
|
|
1428
1541
|
”SPACE-HALCA” - specific orientation model."""
|
|
1429
1542
|
telescope_name: Coord[AntennaName, str]
|
|
1430
1543
|
""" Useful when data is combined from mutiple arrays for example ACA + ALMA. """
|
|
@@ -1477,12 +1590,14 @@ class PhaseCalibrationXds:
|
|
|
1477
1590
|
""" Name of the station pad (relevant to arrays with moving antennas). """
|
|
1478
1591
|
mount: Coord[AntennaName, str]
|
|
1479
1592
|
""" Mount type of the antenna. Reserved keywords include: ”EQUATORIAL” - equatorial mount;
|
|
1480
|
-
”ALT-AZ
|
|
1481
|
-
"ALT-AZ+ROTATOR"
|
|
1593
|
+
”ALT-AZ”: azimuth-elevation mount;
|
|
1594
|
+
"ALT-AZ+ROTATOR": alt-az mount with feed rotator; introduced for ASKAP dishes;
|
|
1482
1595
|
"ALT-AZ+NASMYTH-R": Nasmyth mount with receivers at the right-hand side of the cabin. Many high-frequency antennas used for VLBI have such a mount typel;
|
|
1483
|
-
"ALT-AZ+NASMYTH-L
|
|
1484
|
-
|
|
1485
|
-
|
|
1596
|
+
"ALT-AZ+NASMYTH-L": Nasmyth mount with receivers at the left-hand side of the cabin.
|
|
1597
|
+
"ALT-AZ+BWG-R": alt-az mount that uses a Beam Wave Guide to bring the focus down to the pedestal. The receivers are at the right-hand side of the cabin (-R). Compared to the Nasmyth mounts there is an extra correction term because there are now two rotating mirrors. See https://arxiv.org/abs/2210.13381 for more details.
|
|
1598
|
+
"ALT-AZ+BWG-L": alt-az mount that uses a Beam Wave Guide, as above, but with receivers at the left-hand side of the cabin.
|
|
1599
|
+
”X-Y”: x-y mount;
|
|
1600
|
+
”SPACE-HALCA”: specific orientation model."""
|
|
1486
1601
|
telescope_name: Coord[AntennaName, str]
|
|
1487
1602
|
""" Useful when data is combined from mutiple arrays for example ACA + ALMA. """
|
|
1488
1603
|
receptor_label: Coord[ReceptorLabel, str]
|
|
@@ -1778,7 +1893,7 @@ class SystemCalibrationXds:
|
|
|
1778
1893
|
""" Midpoint of time for which this set of parameters is accurate. Labeled 'time' when interpolating to main time axis """
|
|
1779
1894
|
time_system_cal: Optional[Coordof[TimeSystemCalCoordArray]] = None
|
|
1780
1895
|
""" Midpoint of time for which this set of parameters is accurate. Labeled 'time_system_cal' when not interpolating to main time axis """
|
|
1781
|
-
frequency: Optional[Coordof[
|
|
1896
|
+
frequency: Optional[Coordof[FrequencyArray]] = None
|
|
1782
1897
|
""" """
|
|
1783
1898
|
frequency_system_cal: Optional[Coord[FrequencySystemCal, int]] = None
|
|
1784
1899
|
"""TODO: What is this?"""
|
|
@@ -1915,6 +2030,8 @@ class VisibilityXds:
|
|
|
1915
2030
|
"""
|
|
1916
2031
|
Labels for polarization types, e.g. ``['XX','XY','YX','YY']``, ``['RR','RL','LR','LL']``.
|
|
1917
2032
|
"""
|
|
2033
|
+
field_name: Coordof[Coord[Time, str]]
|
|
2034
|
+
"""Field name."""
|
|
1918
2035
|
|
|
1919
2036
|
# --- Required data variables ---
|
|
1920
2037
|
|
|
@@ -1927,17 +2044,21 @@ class VisibilityXds:
|
|
|
1927
2044
|
"""Antenna name for 2nd antenna in baseline. Maps to ``attrs['antenna_xds'].antenna_name``"""
|
|
1928
2045
|
|
|
1929
2046
|
# --- Required Attributes ---
|
|
1930
|
-
partition_info: Attr[PartitionInfoDict]
|
|
2047
|
+
# partition_info: Attr[PartitionInfoDict]
|
|
1931
2048
|
observation_info: Attr[ObservationInfoDict]
|
|
1932
2049
|
processor_info: Attr[ProcessorInfoDict]
|
|
1933
|
-
|
|
2050
|
+
|
|
2051
|
+
data_groups: Attr[DataGroupsDict]
|
|
2052
|
+
""" Defines groups of correlated data + flag + weight + uvw variables. """
|
|
1934
2053
|
|
|
1935
2054
|
schema_version: Attr[str]
|
|
1936
|
-
"""Semantic version of
|
|
2055
|
+
"""Semantic version of MSv4 data format."""
|
|
2056
|
+
creator: Attr[CreatorDict]
|
|
2057
|
+
"""Creator information (software, version)."""
|
|
1937
2058
|
creation_date: Attr[str]
|
|
1938
|
-
"""Date visibility dataset was created
|
|
2059
|
+
"""Date visibility dataset was created. Format: YYYY-MM-DDTHH:mm:ss.SSS (ISO 8601)"""
|
|
1939
2060
|
|
|
1940
|
-
type: Attr[Literal["visibility"]] = "visibility"
|
|
2061
|
+
type: Attr[Literal["visibility", "radiometer"]] = "visibility"
|
|
1941
2062
|
"""
|
|
1942
2063
|
Dataset type
|
|
1943
2064
|
"""
|
|
@@ -1953,7 +2074,7 @@ class VisibilityXds:
|
|
|
1953
2074
|
uvw_label: Optional[Coordof[UvwLabelArray]] = None
|
|
1954
2075
|
""" u,v,w """
|
|
1955
2076
|
scan_name: Optional[Coord[Time, str]] = None
|
|
1956
|
-
"""
|
|
2077
|
+
"""Scan name to identify data taken in the same logical scan."""
|
|
1957
2078
|
|
|
1958
2079
|
# --- Optional data variables / arrays ---
|
|
1959
2080
|
|
|
@@ -1967,7 +2088,6 @@ class VisibilityXds:
|
|
|
1967
2088
|
Data[
|
|
1968
2089
|
Union[
|
|
1969
2090
|
tuple[Time, BaselineId],
|
|
1970
|
-
tuple[Time, BaselineId, Frequency],
|
|
1971
2091
|
tuple[Time, BaselineId, Frequency, Polarization],
|
|
1972
2092
|
],
|
|
1973
2093
|
QuantityInSecondsArray,
|
|
@@ -1985,21 +2105,12 @@ class VisibilityXds:
|
|
|
1985
2105
|
"""
|
|
1986
2106
|
TIME_CENTROID_EXTRA_PRECISION: Optional[Dataof[TimeSamplingArray]] = None
|
|
1987
2107
|
"""Additional precision for ``TIME_CENTROID``"""
|
|
1988
|
-
EFFECTIVE_CHANNEL_WIDTH: Optional[Dataof[
|
|
2108
|
+
EFFECTIVE_CHANNEL_WIDTH: Optional[Dataof[EffectiveChannelWidthArray]] = None
|
|
1989
2109
|
"""The channel bandwidth that includes the effects of missing data."""
|
|
1990
|
-
FREQUENCY_CENTROID: Optional[Dataof[
|
|
2110
|
+
FREQUENCY_CENTROID: Optional[Dataof[FrequencyCentroidArray]] = None
|
|
1991
2111
|
"""Includes the effects of missing data unlike ``frequency``."""
|
|
1992
2112
|
|
|
1993
2113
|
# --- Optional Attributes ---
|
|
1994
|
-
pointing_xds: Optional[Attr[PointingXds]] = None
|
|
1995
|
-
system_calibration_xds: Optional[Attr[SystemCalibrationXds]] = None
|
|
1996
|
-
gain_curve_xds: Optional[Attr[GainCurveXds]] = None
|
|
1997
|
-
phase_calibration_xds: Optional[Attr[PhaseCalibrationXds]] = None
|
|
1998
|
-
weather_xds: Optional[Attr[WeatherXds]] = None
|
|
1999
|
-
phased_array_xds: Optional[Attr[PhasedArrayXds]] = None
|
|
2000
|
-
|
|
2001
|
-
xradio_version: Optional[Attr[str]] = None
|
|
2002
|
-
""" Version of XRADIO used if converted from MSv2. """
|
|
2003
2114
|
|
|
2004
2115
|
|
|
2005
2116
|
@xarray_dataset_schema
|
|
@@ -2020,21 +2131,27 @@ class SpectrumXds:
|
|
|
2020
2131
|
"""
|
|
2021
2132
|
Labels for polarization types, e.g. ``['XX','XY','YX','YY']``, ``['RR','RL','LR','LL']``.
|
|
2022
2133
|
"""
|
|
2134
|
+
field_name: Coordof[Coord[Time, str]]
|
|
2135
|
+
"""Field name."""
|
|
2023
2136
|
|
|
2024
2137
|
# --- Required data variables ---
|
|
2025
2138
|
SPECTRUM: Dataof[SpectrumArray]
|
|
2026
2139
|
"""Single dish data, either simulated or measured by an antenna."""
|
|
2027
2140
|
|
|
2028
2141
|
# --- Required Attributes ---
|
|
2029
|
-
partition_info: Attr[PartitionInfoDict]
|
|
2142
|
+
# partition_info: Attr[PartitionInfoDict]
|
|
2030
2143
|
observation_info: Attr[ObservationInfoDict]
|
|
2031
2144
|
processor_info: Attr[ProcessorInfoDict]
|
|
2032
|
-
|
|
2145
|
+
|
|
2146
|
+
data_groups: Attr[DataGroupsDict]
|
|
2147
|
+
""" Defines groups of correlated data + flag + weight variables. """
|
|
2033
2148
|
|
|
2034
2149
|
schema_version: Attr[str]
|
|
2035
|
-
"""Semantic version of
|
|
2150
|
+
"""Semantic version of MSv4 data format."""
|
|
2151
|
+
creator: Attr[CreatorDict]
|
|
2152
|
+
"""Creator information (software, version)."""
|
|
2036
2153
|
creation_date: Attr[str]
|
|
2037
|
-
"""Date
|
|
2154
|
+
"""Date spectrum dataset was created . Format: YYYY-MM-DDTHH:mm:ss.SSS (ISO 8601)"""
|
|
2038
2155
|
|
|
2039
2156
|
type: Attr[Literal["spectrum"]] = "spectrum"
|
|
2040
2157
|
"""
|
|
@@ -2062,7 +2179,6 @@ class SpectrumXds:
|
|
|
2062
2179
|
Data[
|
|
2063
2180
|
Union[
|
|
2064
2181
|
tuple[Time, AntennaName],
|
|
2065
|
-
tuple[Time, AntennaName, Frequency],
|
|
2066
2182
|
tuple[Time, AntennaName, Frequency, Polarization],
|
|
2067
2183
|
],
|
|
2068
2184
|
QuantityInSecondsArray,
|
|
@@ -2080,18 +2196,7 @@ class SpectrumXds:
|
|
|
2080
2196
|
"""
|
|
2081
2197
|
TIME_CENTROID_EXTRA_PRECISION: Optional[Dataof[TimeSamplingArray]] = None
|
|
2082
2198
|
"""Additional precision for ``TIME_CENTROID``"""
|
|
2083
|
-
EFFECTIVE_CHANNEL_WIDTH: Optional[Dataof[
|
|
2199
|
+
EFFECTIVE_CHANNEL_WIDTH: Optional[Dataof[EffectiveChannelWidthArray]] = None
|
|
2084
2200
|
"""The channel bandwidth that includes the effects of missing data."""
|
|
2085
|
-
FREQUENCY_CENTROID: Optional[Dataof[
|
|
2201
|
+
FREQUENCY_CENTROID: Optional[Dataof[FrequencyCentroidArray]] = None
|
|
2086
2202
|
"""Includes the effects of missing data unlike ``frequency``."""
|
|
2087
|
-
|
|
2088
|
-
# --- Optional Attributes ---
|
|
2089
|
-
pointing_xds: Optional[Attr[PointingXds]] = None
|
|
2090
|
-
system_calibration_xds: Optional[Attr[SystemCalibrationXds]] = None
|
|
2091
|
-
gain_curve_xds: Optional[Attr[GainCurveXds]] = None
|
|
2092
|
-
phase_calibration_xds: Optional[Attr[PhaseCalibrationXds]] = None
|
|
2093
|
-
weather_xds: Optional[Attr[WeatherXds]] = None
|
|
2094
|
-
phased_array_xds: Optional[Attr[PhasedArrayXds]] = None
|
|
2095
|
-
|
|
2096
|
-
xradio_version: Optional[Attr[str]] = None
|
|
2097
|
-
""" Version of XRADIO used if converted from MSv2. """
|
xradio/schema/bases.py
CHANGED
|
@@ -397,11 +397,15 @@ def xarray_dataset_schema(cls):
|
|
|
397
397
|
cls = dataclasses.dataclass(cls, init=True, repr=False, eq=False, frozen=True)
|
|
398
398
|
|
|
399
399
|
# Make schema
|
|
400
|
-
|
|
400
|
+
schema = dataclass.xarray_dataclass_to_dataset_schema(cls)
|
|
401
|
+
cls.__xradio_dataset_schema = schema
|
|
401
402
|
|
|
402
403
|
# Replace __new__
|
|
403
404
|
cls.__new__ = _dataset_new
|
|
404
405
|
|
|
406
|
+
# Register type
|
|
407
|
+
check.register_dataset_type(schema)
|
|
408
|
+
|
|
405
409
|
return cls
|
|
406
410
|
|
|
407
411
|
|
xradio/schema/check.py
CHANGED
|
@@ -2,6 +2,7 @@ import dataclasses
|
|
|
2
2
|
import typing
|
|
3
3
|
import inspect
|
|
4
4
|
import functools
|
|
5
|
+
import warnings
|
|
5
6
|
|
|
6
7
|
import xarray
|
|
7
8
|
import numpy
|
|
@@ -173,7 +174,9 @@ def check_array(
|
|
|
173
174
|
|
|
174
175
|
|
|
175
176
|
def check_dataset(
|
|
176
|
-
dataset: xarray.Dataset,
|
|
177
|
+
dataset: xarray.Dataset,
|
|
178
|
+
schema: typing.Union[type, metamodel.DatasetSchema],
|
|
179
|
+
allow_superflous_dims: typing.Set[str] = frozenset(),
|
|
177
180
|
) -> SchemaIssues:
|
|
178
181
|
"""
|
|
179
182
|
Check whether an xarray DataArray conforms to a schema
|
|
@@ -196,7 +199,12 @@ def check_dataset(
|
|
|
196
199
|
)
|
|
197
200
|
|
|
198
201
|
# Check dimensions. Order does not matter on datasets
|
|
199
|
-
issues = check_dimensions(
|
|
202
|
+
issues = check_dimensions(
|
|
203
|
+
dataset.dims,
|
|
204
|
+
schema.dimensions,
|
|
205
|
+
check_order=False,
|
|
206
|
+
allow_superflous=allow_superflous_dims,
|
|
207
|
+
)
|
|
200
208
|
|
|
201
209
|
# Check attributes
|
|
202
210
|
issues += check_attributes(dataset.attrs, schema.attributes)
|
|
@@ -211,7 +219,10 @@ def check_dataset(
|
|
|
211
219
|
|
|
212
220
|
|
|
213
221
|
def check_dimensions(
|
|
214
|
-
dims: [str],
|
|
222
|
+
dims: [str],
|
|
223
|
+
expected: [[str]],
|
|
224
|
+
check_order: bool = True,
|
|
225
|
+
allow_superflous: typing.Set[str] = frozenset(),
|
|
215
226
|
) -> SchemaIssues:
|
|
216
227
|
"""
|
|
217
228
|
Check whether a dimension list conforms to a schema
|
|
@@ -230,7 +241,7 @@ def check_dimensions(
|
|
|
230
241
|
exp_dims_set = set(exp_dims)
|
|
231
242
|
|
|
232
243
|
# No match? Continue, but take note of best match
|
|
233
|
-
if exp_dims_set != dims_set:
|
|
244
|
+
if exp_dims_set - allow_superflous != dims_set - allow_superflous:
|
|
234
245
|
diff = len(dims_set.symmetric_difference(exp_dims_set))
|
|
235
246
|
if best is None or diff < best_diff:
|
|
236
247
|
best = exp_dims_set
|
|
@@ -253,7 +264,7 @@ def check_dimensions(
|
|
|
253
264
|
)
|
|
254
265
|
|
|
255
266
|
# Dimensionality not supported - try to give a helpful suggestion
|
|
256
|
-
hint_remove = [f"'{hint}'" for hint in dims_set - best]
|
|
267
|
+
hint_remove = [f"'{hint}'" for hint in (dims_set - best) - allow_superflous]
|
|
257
268
|
hint_add = [f"'{hint}'" for hint in best - dims_set]
|
|
258
269
|
if hint_remove and hint_add:
|
|
259
270
|
message = f"Unexpected coordinates, replace {','.join(hint_remove)} by {','.join(hint_add)}?"
|
|
@@ -560,6 +571,87 @@ def _check_value_union(val, ann):
|
|
|
560
571
|
return args_issues
|
|
561
572
|
|
|
562
573
|
|
|
574
|
+
_DATASET_TYPES = {}
|
|
575
|
+
|
|
576
|
+
|
|
577
|
+
def register_dataset_type(schema: metamodel.DatasetSchema):
|
|
578
|
+
"""
|
|
579
|
+
Registers the given schema for usage with :py:meth:`check_datatree`
|
|
580
|
+
|
|
581
|
+
This looks for a ``type`` attribute in the dataset schema, which
|
|
582
|
+
must have a :py:class:`typing.Literal` type annotation specifying
|
|
583
|
+
the type name of the dataset
|
|
584
|
+
|
|
585
|
+
:param schema: Schema to register
|
|
586
|
+
"""
|
|
587
|
+
|
|
588
|
+
# Find type attribute
|
|
589
|
+
for attr in schema.attributes:
|
|
590
|
+
if attr.name != "type":
|
|
591
|
+
continue
|
|
592
|
+
|
|
593
|
+
# Type should be a kind of literal
|
|
594
|
+
if typing.get_origin(attr.typ) is not typing.Literal:
|
|
595
|
+
warnings.warn(
|
|
596
|
+
f"In dataset schema {schema.schema_name}:"
|
|
597
|
+
'Attribute "type" should be a literal!'
|
|
598
|
+
)
|
|
599
|
+
continue
|
|
600
|
+
|
|
601
|
+
# Register type names
|
|
602
|
+
for typ in typing.get_args(attr.typ):
|
|
603
|
+
_DATASET_TYPES[typ] = schema
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
def check_datatree(
|
|
607
|
+
datatree: xarray.DataTree,
|
|
608
|
+
):
|
|
609
|
+
"""
|
|
610
|
+
Check datatree for schema conformance
|
|
611
|
+
|
|
612
|
+
This is the case if all nodes containing data
|
|
613
|
+
|
|
614
|
+
This looks for a ``type`` attribute in the dataset schema, which
|
|
615
|
+
must have a :py:class:`typing.Literal` type annotation specifying
|
|
616
|
+
the type name of the dataset
|
|
617
|
+
|
|
618
|
+
:param schema: Schema to register
|
|
619
|
+
"""
|
|
620
|
+
|
|
621
|
+
# Loop through all groups in datatree
|
|
622
|
+
issues = SchemaIssues()
|
|
623
|
+
for xds_name in datatree.groups:
|
|
624
|
+
|
|
625
|
+
# Ignore any leaf without data
|
|
626
|
+
node = datatree[xds_name]
|
|
627
|
+
if not node.has_data:
|
|
628
|
+
continue
|
|
629
|
+
|
|
630
|
+
# Look up schema
|
|
631
|
+
schema = _DATASET_TYPES.get(node.attrs.get("type"))
|
|
632
|
+
if schema is None:
|
|
633
|
+
issues.add(
|
|
634
|
+
SchemaIssue(
|
|
635
|
+
[("", xds_name)],
|
|
636
|
+
message="Unknown dataset type!",
|
|
637
|
+
found=typ,
|
|
638
|
+
expected=list(schemas.keys()),
|
|
639
|
+
)
|
|
640
|
+
)
|
|
641
|
+
continue
|
|
642
|
+
|
|
643
|
+
# Determine dimensions inherited from parent
|
|
644
|
+
# (they might show up as "superflous" for the child schema)
|
|
645
|
+
parent_dims = frozenset()
|
|
646
|
+
if node.parent is not None:
|
|
647
|
+
parent_dims = set(node.parent.dims)
|
|
648
|
+
|
|
649
|
+
# Check schema
|
|
650
|
+
issues += check_dataset(node.dataset, schema, parent_dims).at_path("", xds_name)
|
|
651
|
+
|
|
652
|
+
return issues
|
|
653
|
+
|
|
654
|
+
|
|
563
655
|
def schema_checked(fn, check_parameters: bool = True, check_return: bool = True):
|
|
564
656
|
"""
|
|
565
657
|
Function decorator to check parameters and return value for
|