xradio 0.0.27__py3-none-any.whl → 0.0.29__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 +5 -4
- xradio/_utils/array.py +90 -0
- xradio/_utils/zarr/common.py +48 -3
- xradio/image/_util/_fits/xds_from_fits.py +10 -5
- xradio/image/_util/_zarr/zarr_low_level.py +27 -24
- xradio/image/_util/common.py +4 -1
- xradio/image/_util/zarr.py +4 -1
- xradio/schema/__init__.py +24 -6
- xradio/schema/bases.py +440 -2
- xradio/schema/check.py +96 -55
- xradio/schema/dataclass.py +123 -27
- xradio/schema/metamodel.py +21 -4
- xradio/schema/typing.py +33 -18
- xradio/vis/__init__.py +5 -2
- xradio/vis/_processing_set.py +30 -9
- xradio/vis/_vis_utils/_ms/_tables/create_field_and_source_xds.py +710 -0
- xradio/vis/_vis_utils/_ms/_tables/load.py +23 -10
- xradio/vis/_vis_utils/_ms/_tables/load_main_table.py +145 -64
- xradio/vis/_vis_utils/_ms/_tables/read.py +782 -156
- xradio/vis/_vis_utils/_ms/_tables/read_main_table.py +176 -45
- xradio/vis/_vis_utils/_ms/_tables/read_subtables.py +79 -28
- xradio/vis/_vis_utils/_ms/_tables/write.py +102 -45
- xradio/vis/_vis_utils/_ms/_tables/write_exp_api.py +127 -65
- xradio/vis/_vis_utils/_ms/chunks.py +58 -21
- xradio/vis/_vis_utils/_ms/conversion.py +536 -67
- xradio/vis/_vis_utils/_ms/descr.py +52 -20
- xradio/vis/_vis_utils/_ms/msv2_to_msv4_meta.py +70 -35
- xradio/vis/_vis_utils/_ms/msv4_infos.py +0 -59
- xradio/vis/_vis_utils/_ms/msv4_sub_xdss.py +76 -9
- xradio/vis/_vis_utils/_ms/optimised_functions.py +0 -46
- xradio/vis/_vis_utils/_ms/partition_queries.py +308 -119
- xradio/vis/_vis_utils/_ms/partitions.py +82 -25
- xradio/vis/_vis_utils/_ms/subtables.py +32 -14
- xradio/vis/_vis_utils/_utils/partition_attrs.py +30 -11
- xradio/vis/_vis_utils/_utils/xds_helper.py +136 -45
- xradio/vis/_vis_utils/_zarr/read.py +60 -22
- xradio/vis/_vis_utils/_zarr/write.py +83 -9
- xradio/vis/_vis_utils/ms.py +48 -29
- xradio/vis/_vis_utils/zarr.py +44 -20
- xradio/vis/convert_msv2_to_processing_set.py +106 -32
- xradio/vis/load_processing_set.py +38 -61
- xradio/vis/read_processing_set.py +62 -96
- xradio/vis/schema.py +687 -0
- xradio/vis/vis_io.py +75 -43
- {xradio-0.0.27.dist-info → xradio-0.0.29.dist-info}/LICENSE.txt +6 -1
- {xradio-0.0.27.dist-info → xradio-0.0.29.dist-info}/METADATA +10 -5
- xradio-0.0.29.dist-info/RECORD +73 -0
- {xradio-0.0.27.dist-info → xradio-0.0.29.dist-info}/WHEEL +1 -1
- xradio/vis/model.py +0 -497
- xradio-0.0.27.dist-info/RECORD +0 -71
- {xradio-0.0.27.dist-info → xradio-0.0.29.dist-info}/top_level.txt +0 -0
|
@@ -3,28 +3,37 @@ from typing import Dict, Union
|
|
|
3
3
|
|
|
4
4
|
import numpy as np
|
|
5
5
|
import pandas as pd
|
|
6
|
+
import xarray as xr
|
|
6
7
|
|
|
7
8
|
from ._tables.read import read_generic_table, read_flat_col_chunk
|
|
8
9
|
from ._tables.table_query import open_query, open_table_ro
|
|
9
|
-
from xradio.
|
|
10
|
+
from xradio._utils.array import unique_1d
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
def describe_ms(
|
|
13
|
-
infile: str, mode="summary", rowmap: Union[dict, None] = None
|
|
14
|
+
infile: str, mode: str = "summary", rowmap: Union[dict, None] = None
|
|
14
15
|
) -> Union[pd.DataFrame, Dict]:
|
|
15
16
|
"""
|
|
16
17
|
Summarize the contents of an MS directory in casacore table format
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
infile : str
|
|
22
|
+
input MS filename
|
|
23
|
+
mode : str (Default value = "summary")
|
|
24
|
+
type of information returned ('summary', 'flat', 'expanded').
|
|
25
|
+
'summary' returns a pandas dataframe that is nice for displaying in notebooks
|
|
26
|
+
etc. 'flat' returns a list of tuples of (ddi, row, chan, pol). 'expanded'
|
|
27
|
+
returns a list of tuples of (ddi, time, baseline, chan, pol). These latter two
|
|
28
|
+
are good for trying to determine chunk size for read_ms(expand=True/False). (Default value = "summary")
|
|
29
|
+
rowmap : Union[dict, None] (Default value = None)
|
|
30
|
+
dict of DDI to tuple of (row indices, channel indices). Returned
|
|
31
|
+
by ms_selection function. Default None ignores selections
|
|
32
|
+
|
|
33
|
+
Returns
|
|
34
|
+
-------
|
|
35
|
+
Union[pd.DataFrame, Dict]
|
|
36
|
+
summary as a pd dataframe
|
|
28
37
|
"""
|
|
29
38
|
infile = os.path.expanduser(infile) # does nothing if $HOME is unknown
|
|
30
39
|
if not os.path.isdir(infile):
|
|
@@ -38,18 +47,22 @@ def describe_ms(
|
|
|
38
47
|
|
|
39
48
|
ddi_xds = read_generic_table(infile, "DATA_DESCRIPTION")
|
|
40
49
|
ddis = list(ddi_xds.row.values) if rowmap is None else list(rowmap.keys())
|
|
41
|
-
|
|
42
50
|
summary: Union[pd.DataFrame, Dict] = []
|
|
43
51
|
if mode == "summary":
|
|
44
52
|
summary = pd.DataFrame([])
|
|
45
53
|
|
|
54
|
+
all_sdf = []
|
|
46
55
|
with open_table_ro(infile) as tb_tool:
|
|
47
56
|
for ddi in ddis:
|
|
48
57
|
taql = f"select * from $tb_tool where DATA_DESC_ID = {ddi}"
|
|
49
58
|
with open_query(tb_tool, taql) as query_per_ddi:
|
|
50
|
-
populate_ms_descr(
|
|
59
|
+
sdf = populate_ms_descr(
|
|
60
|
+
infile, mode, query_per_ddi, summary, ddi, ddi_xds
|
|
61
|
+
)
|
|
62
|
+
all_sdf.append(sdf)
|
|
51
63
|
|
|
52
64
|
if mode == "summary":
|
|
65
|
+
summary = pd.DataFrame(all_sdf)
|
|
53
66
|
summary = summary.set_index("ddi").sort_index()
|
|
54
67
|
else:
|
|
55
68
|
summary = dict(summary)
|
|
@@ -57,16 +70,35 @@ def describe_ms(
|
|
|
57
70
|
|
|
58
71
|
|
|
59
72
|
def populate_ms_descr(
|
|
60
|
-
infile
|
|
73
|
+
infile: str,
|
|
74
|
+
mode: str,
|
|
75
|
+
query_per_ddi,
|
|
76
|
+
summary: dict,
|
|
77
|
+
ddi: int,
|
|
78
|
+
ddi_xds: xr.Dataset,
|
|
79
|
+
rowmap: Union[Dict, None] = None,
|
|
61
80
|
) -> pd.DataFrame:
|
|
62
|
-
"""
|
|
81
|
+
"""
|
|
82
|
+
Adds information from the time and baseline (antenna1+antenna2)
|
|
63
83
|
columns as well as channel and polarizations, based on a taql
|
|
64
84
|
query.
|
|
65
85
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
86
|
+
Parameters
|
|
87
|
+
----------
|
|
88
|
+
infile : str
|
|
89
|
+
input table/MS path
|
|
90
|
+
mode : str
|
|
91
|
+
mode (as in describe_ms())
|
|
92
|
+
query_per_ddi :
|
|
93
|
+
a TaQL query with data per individual DDI
|
|
94
|
+
summary : Dict
|
|
95
|
+
summary dict being populated
|
|
96
|
+
ddi_xds : xr.Dataset
|
|
97
|
+
final summary object being populated from the invividual sdf's
|
|
98
|
+
|
|
99
|
+
Returns
|
|
100
|
+
-------
|
|
101
|
+
pd.DataFrame
|
|
70
102
|
"""
|
|
71
103
|
spw_ids = ddi_xds.spectral_window_id.values
|
|
72
104
|
pol_ids = ddi_xds.polarization_id.values
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import graphviper.utils.logger as logger
|
|
2
|
+
|
|
1
3
|
col_to_data_variable_names = {
|
|
2
4
|
"FLOAT_DATA": "SPECTRUM",
|
|
3
5
|
"DATA": "VISIBILITY",
|
|
@@ -26,17 +28,38 @@ col_to_coord_names = {
|
|
|
26
28
|
"ANTENNA2": "baseline_ant2_id",
|
|
27
29
|
}
|
|
28
30
|
|
|
31
|
+
# Map casacore measures to astropy
|
|
29
32
|
casacore_to_msv4_measure_type = {
|
|
30
|
-
"quanta": {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
33
|
+
"quanta": {
|
|
34
|
+
"type": "quantity",
|
|
35
|
+
},
|
|
36
|
+
"direction": {"type": "sky_coord", "Ref": "frame", "Ref_map": {"J2000": "fk5"}},
|
|
37
|
+
"epoch": {"type": "time", "Ref": "scale", "Ref_map": {"UTC": "utc"}},
|
|
38
|
+
"frequency": {
|
|
39
|
+
"type": "spectral_coord",
|
|
40
|
+
"Ref": "frame",
|
|
41
|
+
"Ref_map": {
|
|
42
|
+
"REST": "REST",
|
|
43
|
+
"LSRK": "LSRK",
|
|
44
|
+
"LSRD": "LSRD",
|
|
45
|
+
"BARY": "BARY",
|
|
46
|
+
"GEO": "GEO",
|
|
47
|
+
"TOPO": "TOPO",
|
|
48
|
+
"GALACTO": "GALACTO",
|
|
49
|
+
"LGROUP": "LGROUP",
|
|
50
|
+
"CMB": "CMB",
|
|
51
|
+
"Undefined": "Undefined",
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
"position": {
|
|
55
|
+
"type": "earth_location",
|
|
56
|
+
"Ref": "ellipsoid",
|
|
57
|
+
"Ref_map": {"ITRF": "GRS80"},
|
|
58
|
+
},
|
|
59
|
+
"uvw": {"type": "uvw", "Ref": "frame", "Ref_map": {"ITRF": "GRS80"}},
|
|
60
|
+
"radialvelocity": {"type": "quantity"},
|
|
36
61
|
}
|
|
37
62
|
|
|
38
|
-
casacore_to_msv4_ref = {"J2000": "FK5", "ITRF": "GRS80"}
|
|
39
|
-
|
|
40
63
|
casa_frequency_frames = [
|
|
41
64
|
"REST",
|
|
42
65
|
"LSRK",
|
|
@@ -54,48 +77,60 @@ casa_frequency_frames_codes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 64]
|
|
|
54
77
|
|
|
55
78
|
|
|
56
79
|
def column_description_casacore_to_msv4_measure(
|
|
57
|
-
casacore_column_description, ref_code=None, time_format="
|
|
80
|
+
casacore_column_description, ref_code=None, time_format="UNIX"
|
|
58
81
|
):
|
|
59
82
|
import numpy as np
|
|
60
83
|
|
|
61
84
|
msv4_measure = {}
|
|
62
85
|
if "MEASINFO" in casacore_column_description["keywords"]:
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
86
|
+
measinfo = casacore_column_description["keywords"]["MEASINFO"]
|
|
87
|
+
|
|
88
|
+
# Get conversion information
|
|
89
|
+
msv4_measure_conversion = casacore_to_msv4_measure_type[measinfo["type"]]
|
|
90
|
+
|
|
91
|
+
# Convert type, copy unit
|
|
92
|
+
msv4_measure["type"] = msv4_measure_conversion["type"]
|
|
66
93
|
msv4_measure["units"] = list(
|
|
67
94
|
casacore_column_description["keywords"]["QuantumUnits"]
|
|
68
95
|
)
|
|
69
96
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
if "Ref" in casacore_column_description["keywords"]["MEASINFO"]:
|
|
80
|
-
casa_ref = casacore_column_description["keywords"]["MEASINFO"]["Ref"]
|
|
81
|
-
elif (
|
|
82
|
-
casacore_column_description["keywords"]["MEASINFO"]["type"]
|
|
83
|
-
== "frequency"
|
|
84
|
-
):
|
|
97
|
+
# Reference frame to convert?
|
|
98
|
+
if "Ref" in msv4_measure_conversion:
|
|
99
|
+
# Find reference frame
|
|
100
|
+
if "TabRefCodes" in measinfo:
|
|
101
|
+
ref_index = np.where(measinfo["TabRefCodes"] == ref_code)[0][0]
|
|
102
|
+
casa_ref = measinfo["TabRefTypes"][ref_index]
|
|
103
|
+
elif "Ref" in measinfo:
|
|
104
|
+
casa_ref = measinfo["Ref"]
|
|
105
|
+
elif measinfo["type"] == "frequency":
|
|
85
106
|
# Some MSv2 don't have the "TabRefCodes".
|
|
86
107
|
ref_index = np.where(casa_frequency_frames_codes == ref_code)[0][0]
|
|
87
108
|
casa_ref = casa_frequency_frames[ref_index]
|
|
109
|
+
else:
|
|
110
|
+
logger.warning(
|
|
111
|
+
f"Could not determine {measinfo['type']} measure "
|
|
112
|
+
"reference frame!"
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
# Convert into MSv4 representation of reference frame, warn if unknown
|
|
116
|
+
if casa_ref in msv4_measure_conversion.get("Ref_map", {}):
|
|
117
|
+
casa_ref = msv4_measure_conversion["Ref_map"][casa_ref]
|
|
118
|
+
else:
|
|
119
|
+
logger.warning(
|
|
120
|
+
f"Unknown reference frame for {measinfo['type']} "
|
|
121
|
+
f"measure, using verbatim: {casa_ref}"
|
|
122
|
+
)
|
|
88
123
|
|
|
89
|
-
|
|
90
|
-
casa_ref = casacore_to_msv4_ref[casa_ref]
|
|
91
|
-
msv4_measure[
|
|
92
|
-
casacore_to_msv4_measure_type[
|
|
93
|
-
casacore_column_description["keywords"]["MEASINFO"]["type"]
|
|
94
|
-
]["Ref"]
|
|
95
|
-
] = casa_ref
|
|
124
|
+
msv4_measure[msv4_measure_conversion["Ref"]] = casa_ref
|
|
96
125
|
|
|
97
126
|
if msv4_measure["type"] == "time":
|
|
98
|
-
msv4_measure["format"] =
|
|
127
|
+
msv4_measure["format"] = time_format
|
|
128
|
+
elif "QuantumUnits" in casacore_column_description["keywords"]:
|
|
129
|
+
msv4_measure = {
|
|
130
|
+
"type": "quantity",
|
|
131
|
+
"units": list(casacore_column_description["keywords"]["QuantumUnits"]),
|
|
132
|
+
}
|
|
133
|
+
|
|
99
134
|
return msv4_measure
|
|
100
135
|
|
|
101
136
|
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
from .msv2_to_msv4_meta import column_description_casacore_to_msv4_measure
|
|
2
|
-
from .subtables import subt_rename_ids
|
|
3
|
-
from ._tables.read import read_generic_table
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def create_field_info(in_file, field_id):
|
|
7
|
-
field_xds = read_generic_table(
|
|
8
|
-
in_file,
|
|
9
|
-
"FIELD",
|
|
10
|
-
rename_ids=subt_rename_ids["FIELD"],
|
|
11
|
-
).sel(field_id=field_id)
|
|
12
|
-
# https://stackoverflow.com/questions/53195684/how-to-navigate-a-dict-by-list-of-keys
|
|
13
|
-
|
|
14
|
-
field_column_description = field_xds.attrs["other"]["msv2"]["ctds_attrs"][
|
|
15
|
-
"column_descriptions"
|
|
16
|
-
]
|
|
17
|
-
# ['DELAY_DIR', 'PHASE_DIR', 'REFERENCE_DIR', 'CODE', 'FLAG_ROW', 'NAME', 'NUM_POLY', 'SOURCE_ID', 'TIME']
|
|
18
|
-
|
|
19
|
-
msv4_measure = column_description_casacore_to_msv4_measure(
|
|
20
|
-
field_column_description["REFERENCE_DIR"],
|
|
21
|
-
ref_code=getattr(field_xds.get("refdir_ref"), "data", None),
|
|
22
|
-
)
|
|
23
|
-
delay_dir = {
|
|
24
|
-
"dims": "",
|
|
25
|
-
"data": list(field_xds["delay_dir"].data[0, :]),
|
|
26
|
-
"attrs": msv4_measure,
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
msv4_measure = column_description_casacore_to_msv4_measure(
|
|
30
|
-
field_column_description["PHASE_DIR"],
|
|
31
|
-
ref_code=getattr(field_xds.get("phasedir_ref"), "data", None),
|
|
32
|
-
)
|
|
33
|
-
phase_dir = {
|
|
34
|
-
"dims": "",
|
|
35
|
-
"data": list(field_xds["phase_dir"].data[0, :]),
|
|
36
|
-
"attrs": msv4_measure,
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
msv4_measure = column_description_casacore_to_msv4_measure(
|
|
40
|
-
field_column_description["DELAY_DIR"],
|
|
41
|
-
ref_code=getattr(field_xds.get("delaydir_ref"), "data", None),
|
|
42
|
-
)
|
|
43
|
-
reference_dir = {
|
|
44
|
-
"dims": "",
|
|
45
|
-
"data": list(field_xds["delay_dir"].data[0, :]),
|
|
46
|
-
"attrs": msv4_measure,
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
field_info = {
|
|
50
|
-
"name": str(field_xds["name"].data),
|
|
51
|
-
"code": str(field_xds["code"].data),
|
|
52
|
-
"delay_direction": delay_dir,
|
|
53
|
-
"phase_direction": phase_dir,
|
|
54
|
-
"reference_direction": reference_dir,
|
|
55
|
-
"field_id": field_id,
|
|
56
|
-
}
|
|
57
|
-
# xds.attrs["field_info"] = field_info
|
|
58
|
-
|
|
59
|
-
return field_info
|
|
@@ -1,13 +1,61 @@
|
|
|
1
|
+
import graphviper.utils.logger as logger
|
|
2
|
+
import time
|
|
3
|
+
from typing import Tuple, Union
|
|
4
|
+
|
|
1
5
|
import numpy as np
|
|
2
6
|
import xarray as xr
|
|
3
7
|
|
|
4
8
|
from .msv2_to_msv4_meta import column_description_casacore_to_msv4_measure
|
|
5
9
|
from .subtables import subt_rename_ids
|
|
6
|
-
from ._tables.read import read_generic_table
|
|
10
|
+
from ._tables.read import make_taql_where_between_min_max, read_generic_table
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def interpolate_to_time(
|
|
14
|
+
xds: xr.Dataset, interp_time: Union[xr.DataArray, None], message_prefix: str
|
|
15
|
+
) -> xr.Dataset:
|
|
16
|
+
"""
|
|
17
|
+
Interpolate the time coordinate of the input xarray dataset to the
|
|
18
|
+
a data array. This can be used for example to interpolate a pointing_xds
|
|
19
|
+
to the time coord of the (main) MSv4, or similarly the ephemeris
|
|
20
|
+
data variables of a field_and_source_xds.
|
|
21
|
+
|
|
22
|
+
Uses interpolation method "linear", unless the source number of points is
|
|
23
|
+
1 in which case "nearest" is used, to avoid divide-by-zero issues.
|
|
24
|
+
|
|
25
|
+
Parameters:
|
|
26
|
+
----------
|
|
27
|
+
xds : xr.Dataset
|
|
28
|
+
Xarray dataset to interpolate (presumably a pointing_xds or an xds of
|
|
29
|
+
ephemeris variables)
|
|
30
|
+
interp_time : Union[xr.DataArray, None]
|
|
31
|
+
Time axis to interpolate the dataset to (usually main MSv4 time)
|
|
32
|
+
message_prefix: str
|
|
33
|
+
A prefix for info/debug/etc. messages
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
-------
|
|
37
|
+
interpolated_xds : xr.Dataset
|
|
38
|
+
xarray dataset with time axis interpolated to interp_time.
|
|
39
|
+
"""
|
|
40
|
+
if interp_time is not None:
|
|
41
|
+
points_before = xds.time.size
|
|
42
|
+
if points_before > 1:
|
|
43
|
+
method = "linear"
|
|
44
|
+
else:
|
|
45
|
+
method = "nearest"
|
|
46
|
+
xds = xds.interp(time=interp_time, method=method, assume_sorted=True)
|
|
47
|
+
points_after = xds.time.size
|
|
48
|
+
logger.debug(
|
|
49
|
+
f"{message_prefix}: interpolating the time coordinate "
|
|
50
|
+
f"from {points_before} to {points_after} points"
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
return xds
|
|
7
54
|
|
|
8
55
|
|
|
9
56
|
def create_ant_xds(in_file: str):
|
|
10
|
-
"""
|
|
57
|
+
"""
|
|
58
|
+
Creates an Antenna Xarray Dataset from a MS v2 ANTENNA table.
|
|
11
59
|
|
|
12
60
|
Parameters
|
|
13
61
|
----------
|
|
@@ -16,7 +64,7 @@ def create_ant_xds(in_file: str):
|
|
|
16
64
|
|
|
17
65
|
Returns
|
|
18
66
|
-------
|
|
19
|
-
|
|
67
|
+
xr.Dataset
|
|
20
68
|
Antenna Xarray Dataset.
|
|
21
69
|
"""
|
|
22
70
|
# Dictionaries that define the conversion from MSv2 to MSv4:
|
|
@@ -90,7 +138,8 @@ def create_ant_xds(in_file: str):
|
|
|
90
138
|
|
|
91
139
|
|
|
92
140
|
def create_weather_xds(in_file: str):
|
|
93
|
-
"""
|
|
141
|
+
"""
|
|
142
|
+
Creates a Weather Xarray Dataset from a MS v2 WEATHER table.
|
|
94
143
|
|
|
95
144
|
Parameters
|
|
96
145
|
----------
|
|
@@ -99,7 +148,7 @@ def create_weather_xds(in_file: str):
|
|
|
99
148
|
|
|
100
149
|
Returns
|
|
101
150
|
-------
|
|
102
|
-
|
|
151
|
+
xr.Dataset
|
|
103
152
|
Weather Xarray Dataset.
|
|
104
153
|
"""
|
|
105
154
|
# Dictionaries that define the conversion from MSv2 to MSv4:
|
|
@@ -209,8 +258,13 @@ def create_weather_xds(in_file: str):
|
|
|
209
258
|
return weather_xds
|
|
210
259
|
|
|
211
260
|
|
|
212
|
-
def create_pointing_xds(
|
|
213
|
-
|
|
261
|
+
def create_pointing_xds(
|
|
262
|
+
in_file: str,
|
|
263
|
+
time_min_max: Union[Tuple[np.float64, np.float64], None],
|
|
264
|
+
interp_time: Union[xr.DataArray, None] = None,
|
|
265
|
+
) -> xr.Dataset:
|
|
266
|
+
"""
|
|
267
|
+
Creates a Pointing Xarray Dataset from an MS v2 POINTING (sub)table.
|
|
214
268
|
|
|
215
269
|
WIP: details of a few direction variables (and possibly moving some to attributes) to be
|
|
216
270
|
settled (see MSv4 spreadsheet).
|
|
@@ -219,12 +273,17 @@ def create_pointing_xds(in_file: str):
|
|
|
219
273
|
----------
|
|
220
274
|
in_file : str
|
|
221
275
|
Input MS name.
|
|
276
|
+
time_min_max : tuple
|
|
277
|
+
min / max times values to constrain loading (from the TIME column)
|
|
278
|
+
interp_time : Union[xr.DataArray, None] (Default value = None)
|
|
279
|
+
interpolate time to this (presumably main dataset time)
|
|
222
280
|
|
|
223
281
|
Returns
|
|
224
282
|
-------
|
|
225
|
-
|
|
226
|
-
|
|
283
|
+
xr.Dataset
|
|
284
|
+
Pointing Xarray dataset
|
|
227
285
|
"""
|
|
286
|
+
start = time.time()
|
|
228
287
|
|
|
229
288
|
# Dictionaries that define the conversion from MSv2 to MSv4:
|
|
230
289
|
to_new_data_variable_names = {
|
|
@@ -257,11 +316,15 @@ def create_pointing_xds(in_file: str):
|
|
|
257
316
|
to_new_coord_names = {"ra/dec": "direction"}
|
|
258
317
|
coord_dims = {}
|
|
259
318
|
|
|
319
|
+
taql_time_range = make_taql_where_between_min_max(
|
|
320
|
+
time_min_max, in_file, "POINTING", "TIME"
|
|
321
|
+
)
|
|
260
322
|
# Read POINTING table into a Xarray Dataset.
|
|
261
323
|
generic_pointing_xds = read_generic_table(
|
|
262
324
|
in_file,
|
|
263
325
|
"POINTING",
|
|
264
326
|
rename_ids=subt_rename_ids["POINTING"],
|
|
327
|
+
taql_where=taql_time_range,
|
|
265
328
|
)
|
|
266
329
|
if not generic_pointing_xds.data_vars:
|
|
267
330
|
# apparently empty MS/POINTING table => produce empty xds
|
|
@@ -319,4 +382,8 @@ def create_pointing_xds(in_file: str):
|
|
|
319
382
|
}
|
|
320
383
|
# TODO: move also source_offset/pointing_offset from data_vars to attrs?
|
|
321
384
|
|
|
385
|
+
pointing_xds = interpolate_to_time(pointing_xds, interp_time, "pointing_xds")
|
|
386
|
+
|
|
387
|
+
logger.debug(f"create_pointing_xds() execution time {time.time() - start:0.2f} s")
|
|
388
|
+
|
|
322
389
|
return pointing_xds
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
"""Contains optimised functions to be used within other modules."""
|
|
2
|
-
|
|
3
|
-
import numpy as np
|
|
4
|
-
import pandas as pd
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def unique_1d(array: np.ndarray) -> np.ndarray:
|
|
8
|
-
"""Optimised version of np.unique for 1D arrays.
|
|
9
|
-
|
|
10
|
-
Args:
|
|
11
|
-
array (np.ndarray): a 1D array of values.
|
|
12
|
-
|
|
13
|
-
Returns:
|
|
14
|
-
np.ndarray: a sorted array of unique values.
|
|
15
|
-
"""
|
|
16
|
-
return np.sort(pd.unique(array))
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def pairing_function(antenna_pairs: np.ndarray) -> np.ndarray:
|
|
20
|
-
"""Pairing function to convert each array pair to a single value.
|
|
21
|
-
|
|
22
|
-
This custom pairing function will only work if the maximum value is less
|
|
23
|
-
than 2**20 and less than 2,048 if using signed 32-bit integers.
|
|
24
|
-
|
|
25
|
-
Args:
|
|
26
|
-
antenna_pairs (np.ndarray): a 2D array containing antenna 1 and antenna
|
|
27
|
-
2 ids, which forms a baseline.
|
|
28
|
-
|
|
29
|
-
Returns:
|
|
30
|
-
np.ndarray: a 1D array of the paired values.
|
|
31
|
-
"""
|
|
32
|
-
return antenna_pairs[:, 0] * 2**20 + antenna_pairs[:, 1]
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def inverse_pairing_function(paired_array: np.ndarray) -> np.ndarray:
|
|
36
|
-
"""Inverse pairing function to convert each paired value to an antenna pair.
|
|
37
|
-
|
|
38
|
-
This inverse pairing function is the inverse of the custom pairing function.
|
|
39
|
-
|
|
40
|
-
Args:
|
|
41
|
-
paired_array (np.ndarray): a 1D array of the paired values.
|
|
42
|
-
|
|
43
|
-
Returns:
|
|
44
|
-
np.ndarray: a 2D array containing antenna 1 and antenna 2 ids.
|
|
45
|
-
"""
|
|
46
|
-
return np.column_stack(np.divmod(paired_array, 2**20))
|