xradio 0.0.56__py3-none-any.whl → 0.0.59__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 +2 -2
- xradio/_utils/_casacore/casacore_from_casatools.py +12 -2
- xradio/_utils/_casacore/tables.py +1 -0
- xradio/_utils/coord_math.py +22 -23
- xradio/_utils/dict_helpers.py +76 -11
- xradio/_utils/schema.py +5 -2
- xradio/_utils/zarr/common.py +1 -73
- xradio/image/_util/_casacore/xds_from_casacore.py +49 -33
- xradio/image/_util/_casacore/xds_to_casacore.py +41 -14
- xradio/image/_util/_fits/xds_from_fits.py +146 -35
- xradio/image/_util/casacore.py +4 -3
- xradio/image/_util/common.py +4 -4
- xradio/image/_util/image_factory.py +8 -8
- xradio/image/image.py +45 -5
- xradio/measurement_set/__init__.py +19 -9
- xradio/measurement_set/_utils/__init__.py +1 -3
- xradio/measurement_set/_utils/_msv2/__init__.py +0 -0
- xradio/measurement_set/_utils/_msv2/_tables/read.py +17 -76
- xradio/measurement_set/_utils/_msv2/_tables/read_main_table.py +2 -685
- xradio/measurement_set/_utils/_msv2/conversion.py +174 -156
- xradio/measurement_set/_utils/_msv2/create_antenna_xds.py +9 -16
- xradio/measurement_set/_utils/_msv2/create_field_and_source_xds.py +128 -222
- xradio/measurement_set/_utils/_msv2/msv2_to_msv4_meta.py +1 -2
- xradio/measurement_set/_utils/_msv2/msv4_info_dicts.py +8 -7
- xradio/measurement_set/_utils/_msv2/msv4_sub_xdss.py +31 -74
- xradio/measurement_set/_utils/_msv2/partition_queries.py +1 -261
- xradio/measurement_set/_utils/_msv2/subtables.py +0 -107
- xradio/measurement_set/_utils/_utils/interpolate.py +60 -0
- xradio/measurement_set/_utils/_zarr/encoding.py +2 -7
- xradio/measurement_set/convert_msv2_to_processing_set.py +0 -2
- xradio/measurement_set/load_processing_set.py +2 -2
- xradio/measurement_set/measurement_set_xdt.py +20 -16
- xradio/measurement_set/open_processing_set.py +1 -3
- xradio/measurement_set/processing_set_xdt.py +54 -841
- xradio/measurement_set/schema.py +122 -132
- xradio/schema/check.py +95 -101
- xradio/schema/dataclass.py +159 -22
- xradio/schema/export.py +99 -0
- xradio/schema/metamodel.py +51 -16
- xradio/schema/typing.py +5 -5
- xradio/sphinx/schema_table.py +41 -77
- {xradio-0.0.56.dist-info → xradio-0.0.59.dist-info}/METADATA +20 -5
- xradio-0.0.59.dist-info/RECORD +65 -0
- {xradio-0.0.56.dist-info → xradio-0.0.59.dist-info}/WHEEL +1 -1
- xradio/image/_util/fits.py +0 -13
- xradio/measurement_set/_utils/_msv2/_tables/load.py +0 -66
- xradio/measurement_set/_utils/_msv2/_tables/load_main_table.py +0 -490
- xradio/measurement_set/_utils/_msv2/_tables/read_subtables.py +0 -398
- xradio/measurement_set/_utils/_msv2/_tables/write.py +0 -323
- xradio/measurement_set/_utils/_msv2/_tables/write_exp_api.py +0 -388
- xradio/measurement_set/_utils/_msv2/chunks.py +0 -115
- xradio/measurement_set/_utils/_msv2/descr.py +0 -165
- xradio/measurement_set/_utils/_msv2/msv2_msv3.py +0 -7
- xradio/measurement_set/_utils/_msv2/partitions.py +0 -392
- xradio/measurement_set/_utils/_utils/cds.py +0 -40
- xradio/measurement_set/_utils/_utils/xds_helper.py +0 -404
- xradio/measurement_set/_utils/_zarr/read.py +0 -263
- xradio/measurement_set/_utils/_zarr/write.py +0 -329
- xradio/measurement_set/_utils/msv2.py +0 -106
- xradio/measurement_set/_utils/zarr.py +0 -133
- xradio-0.0.56.dist-info/RECORD +0 -78
- {xradio-0.0.56.dist-info → xradio-0.0.59.dist-info}/licenses/LICENSE.txt +0 -0
- {xradio-0.0.56.dist-info → xradio-0.0.59.dist-info}/top_level.txt +0 -0
|
@@ -18,10 +18,9 @@ from xradio.measurement_set._utils._msv2._tables.read import (
|
|
|
18
18
|
load_generic_table,
|
|
19
19
|
)
|
|
20
20
|
from xradio._utils.list_and_array import cast_to_str, get_pad_value
|
|
21
|
-
|
|
21
|
+
from xradio._utils.dict_helpers import make_quantity_attrs
|
|
22
22
|
from xradio._utils.coord_math import (
|
|
23
23
|
convert_to_si_units,
|
|
24
|
-
add_position_offsets,
|
|
25
24
|
wrap_to_pi,
|
|
26
25
|
)
|
|
27
26
|
|
|
@@ -45,7 +44,7 @@ def create_field_and_source_xds(
|
|
|
45
44
|
is_single_dish: bool,
|
|
46
45
|
time_min_max: Tuple[np.float64, np.float64],
|
|
47
46
|
ephemeris_interpolate: bool = True,
|
|
48
|
-
) -> tuple[xr.Dataset, int]:
|
|
47
|
+
) -> tuple[xr.Dataset, np.ndarray, int]:
|
|
49
48
|
"""
|
|
50
49
|
Create a field and source xarray dataset (xds) from the given input file, field ID, and spectral window ID.
|
|
51
50
|
Data is extracted from the FIELD and SOURCE tables and if there is ephemeris data, it is also extracted.
|
|
@@ -72,6 +71,8 @@ def create_field_and_source_xds(
|
|
|
72
71
|
-------
|
|
73
72
|
field_and_source_xds : xr.Dataset
|
|
74
73
|
The xarray dataset containing the field and source information.
|
|
74
|
+
source_id : np.ndarray[int]
|
|
75
|
+
Source ID(s) corresponding to the field(s)
|
|
75
76
|
num_lines : int
|
|
76
77
|
Sum of num_lines for all unique sources.
|
|
77
78
|
"""
|
|
@@ -158,6 +159,10 @@ def extract_ephemeris_info(
|
|
|
158
159
|
# Consequently a lot of hardcoding is needed to extract the information.
|
|
159
160
|
# https://casadocs.readthedocs.io/en/latest/notebooks/external-data.html
|
|
160
161
|
|
|
162
|
+
xds = xds.assign_coords(
|
|
163
|
+
{"sky_dis_label": ["dist"], "cartesian_pos_label": ["x", "y", "z"]}
|
|
164
|
+
)
|
|
165
|
+
|
|
161
166
|
# Only read data between the min and max times of the visibility data in the MSv4.
|
|
162
167
|
min_max_mjd = (
|
|
163
168
|
convert_casacore_time_to_mjd(time_min_max[0]),
|
|
@@ -214,44 +219,64 @@ def extract_ephemeris_info(
|
|
|
214
219
|
temp_xds = xr.Dataset()
|
|
215
220
|
|
|
216
221
|
# Add mandatory data: OBSERVER_POSITION
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
+
# Convert Observer position to geodetic coordinates
|
|
223
|
+
from astropy import units as u
|
|
224
|
+
from astropy.coordinates import EarthLocation
|
|
225
|
+
from astropy.time import Time
|
|
226
|
+
|
|
227
|
+
# Create an EarthLocation object for the geodetic coordinates
|
|
228
|
+
# Assume that geodetic coordinates are given in degrees and meters
|
|
229
|
+
location = EarthLocation.from_geodetic(
|
|
230
|
+
lon=ephemeris_meta["GeoLong"] * u.deg,
|
|
231
|
+
lat=ephemeris_meta["GeoLat"] * u.deg,
|
|
232
|
+
height=ephemeris_meta["GeoDist"] * u.m,
|
|
233
|
+
ellipsoid="WGS84", # Explicitly specify WGS84
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
# Get the ITRS Cartesian coordinates (x, y, z)
|
|
237
|
+
observer_position = location.itrs.cartesian.xyz
|
|
238
|
+
|
|
222
239
|
temp_xds["OBSERVER_POSITION"] = xr.DataArray(
|
|
223
|
-
observer_position, dims=["
|
|
240
|
+
observer_position, dims=["cartesian_pos_label"]
|
|
224
241
|
)
|
|
225
242
|
temp_xds["OBSERVER_POSITION"].attrs.update(
|
|
226
243
|
{
|
|
227
244
|
"type": "location",
|
|
228
|
-
"units":
|
|
229
|
-
"data": observer_position,
|
|
245
|
+
"units": "m",
|
|
230
246
|
"frame": "ITRS",
|
|
231
247
|
"origin_object_name": "Earth",
|
|
232
248
|
"coordinate_system": ephemeris_meta["obsloc"].lower(),
|
|
233
|
-
"ellipsoid": "WGS84",
|
|
234
249
|
}
|
|
235
|
-
)
|
|
250
|
+
)
|
|
236
251
|
|
|
237
|
-
|
|
238
|
-
temp_xds["SOURCE_LOCATION"] = xr.DataArray(
|
|
252
|
+
temp_xds["SOURCE_DIRECTION"] = xr.DataArray(
|
|
239
253
|
np.column_stack(
|
|
240
254
|
(
|
|
241
255
|
ephemeris_xds["RA"].data,
|
|
242
256
|
ephemeris_xds["DEC"].data,
|
|
243
|
-
ephemeris_xds["Rho"].data,
|
|
244
257
|
)
|
|
245
258
|
),
|
|
246
|
-
dims=["time_ephemeris", "
|
|
259
|
+
dims=["time_ephemeris", "sky_dir_label"],
|
|
247
260
|
)
|
|
261
|
+
|
|
262
|
+
temp_xds["SOURCE_DISTANCE"] = xr.DataArray(
|
|
263
|
+
np.column_stack((ephemeris_xds["Rho"].data,)),
|
|
264
|
+
dims=["time_ephemeris", "sky_dis_label"],
|
|
265
|
+
)
|
|
266
|
+
|
|
248
267
|
# Have to use cast_to_str because the ephemeris table units are not consistently in a list or a string.
|
|
249
|
-
sky_coord_units =
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
]
|
|
254
|
-
|
|
268
|
+
sky_coord_units = cast_to_str(
|
|
269
|
+
ephemeris_column_description["RA"]["keywords"][unit_keyword]
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
temp_xds["SOURCE_DIRECTION"].attrs.update(
|
|
273
|
+
{"type": "sky_coord", "frame": sky_coord_frame, "units": sky_coord_units}
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
sky_coord_units = cast_to_str(
|
|
277
|
+
ephemeris_column_description["Rho"]["keywords"][unit_keyword]
|
|
278
|
+
)
|
|
279
|
+
temp_xds["SOURCE_DISTANCE"].attrs.update(
|
|
255
280
|
{"type": "sky_coord", "frame": sky_coord_frame, "units": sky_coord_units}
|
|
256
281
|
)
|
|
257
282
|
|
|
@@ -281,16 +306,13 @@ def extract_ephemeris_info(
|
|
|
281
306
|
msv4_var_name = msv4_variable_def[0]
|
|
282
307
|
if msv4_var_name in temp_xds:
|
|
283
308
|
temp_xds[msv4_var_name].attrs.update(
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
)
|
|
292
|
-
],
|
|
293
|
-
}
|
|
309
|
+
make_quantity_attrs(
|
|
310
|
+
cast_to_str(
|
|
311
|
+
ephemeris_column_description[generic_var_name]["keywords"][
|
|
312
|
+
unit_keyword
|
|
313
|
+
]
|
|
314
|
+
)
|
|
315
|
+
)
|
|
294
316
|
)
|
|
295
317
|
|
|
296
318
|
# Add optional data: SUB_OBSERVER_DIRECTION and SUB_SOLAR_POSITION
|
|
@@ -307,10 +329,9 @@ def extract_ephemeris_info(
|
|
|
307
329
|
(
|
|
308
330
|
ephemeris_xds[key_lon].data,
|
|
309
331
|
ephemeris_xds[key_lat].data,
|
|
310
|
-
np.zeros(ephemeris_xds[key_lon].shape),
|
|
311
332
|
)
|
|
312
333
|
),
|
|
313
|
-
dims=["time_ephemeris", "
|
|
334
|
+
dims=["time_ephemeris", "ellipsoid_dir_label"],
|
|
314
335
|
)
|
|
315
336
|
|
|
316
337
|
temp_xds["SUB_OBSERVER_DIRECTION"].attrs.update(
|
|
@@ -319,54 +340,55 @@ def extract_ephemeris_info(
|
|
|
319
340
|
"frame": "Undefined",
|
|
320
341
|
"origin_object_name": ephemeris_meta["NAME"],
|
|
321
342
|
"coordinate_system": "planetodetic",
|
|
322
|
-
"units":
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
),
|
|
326
|
-
cast_to_str(
|
|
327
|
-
ephemeris_column_description[key_lat]["keywords"][unit_keyword]
|
|
328
|
-
),
|
|
329
|
-
"m",
|
|
330
|
-
],
|
|
343
|
+
"units": cast_to_str(
|
|
344
|
+
ephemeris_column_description[key_lon]["keywords"][unit_keyword]
|
|
345
|
+
),
|
|
331
346
|
}
|
|
332
347
|
)
|
|
333
348
|
|
|
334
349
|
if "SI_lon" in ephemeris_xds.data_vars:
|
|
335
|
-
temp_xds["
|
|
350
|
+
temp_xds["SUB_SOLAR_DIRECTION"] = xr.DataArray(
|
|
336
351
|
np.column_stack(
|
|
337
352
|
(
|
|
338
353
|
ephemeris_xds["SI_lon"].data,
|
|
339
354
|
ephemeris_xds["SI_lat"].data,
|
|
340
|
-
ephemeris_xds["r"].data,
|
|
341
355
|
)
|
|
342
356
|
),
|
|
343
|
-
dims=["time_ephemeris", "
|
|
357
|
+
dims=["time_ephemeris", "ellipsoid_dir_label"],
|
|
344
358
|
)
|
|
345
|
-
temp_xds["
|
|
359
|
+
temp_xds["SUB_SOLAR_DIRECTION"].attrs.update(
|
|
346
360
|
{
|
|
347
361
|
"type": "location",
|
|
348
362
|
"frame": "Undefined",
|
|
349
363
|
"origin_object_name": "Sun",
|
|
350
364
|
"coordinate_system": "planetodetic",
|
|
351
|
-
"units":
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
365
|
+
"units": cast_to_str(
|
|
366
|
+
ephemeris_column_description["SI_lon"]["keywords"][unit_keyword]
|
|
367
|
+
),
|
|
368
|
+
}
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
temp_xds["SUB_SOLAR_DISTANCE"] = xr.DataArray(
|
|
372
|
+
[ephemeris_xds["r"].data],
|
|
373
|
+
dims=["time_ephemeris", "ellipsoid_dis_label"],
|
|
374
|
+
)
|
|
375
|
+
temp_xds["SUB_SOLAR_DISTANCE"].attrs.update(
|
|
376
|
+
{
|
|
377
|
+
"type": "location",
|
|
378
|
+
"frame": "Undefined",
|
|
379
|
+
"origin_object_name": "Sun",
|
|
380
|
+
"coordinate_system": "planetodetic",
|
|
381
|
+
"units": cast_to_str(
|
|
382
|
+
ephemeris_column_description["r"]["keywords"][unit_keyword]
|
|
383
|
+
),
|
|
362
384
|
}
|
|
363
385
|
)
|
|
364
386
|
|
|
365
387
|
# We are using the "time_ephemeris" label because it might not match the optional time axis of the source and field info. If ephemeris_interpolate=True then rename it to time.
|
|
366
388
|
coords = {
|
|
367
|
-
"
|
|
389
|
+
"ellipsoid_dir_label": ["lon", "lat"],
|
|
390
|
+
"ellipsoid_dis_label": ["dist"],
|
|
368
391
|
"time_ephemeris": ephemeris_xds["time"].data,
|
|
369
|
-
"sky_pos_label": ["ra", "dec", "dist"],
|
|
370
392
|
}
|
|
371
393
|
temp_xds = temp_xds.assign_coords(coords)
|
|
372
394
|
temp_xds["time_ephemeris"].attrs.update(standard_time_coord_attrs)
|
|
@@ -379,10 +401,18 @@ def extract_ephemeris_info(
|
|
|
379
401
|
temp_xds = rename_and_interpolate_to_time(
|
|
380
402
|
temp_xds, "time_ephemeris", interp_time, "field_and_source_xds"
|
|
381
403
|
)
|
|
382
|
-
|
|
404
|
+
source_direction_interp = temp_xds["SOURCE_DIRECTION"]
|
|
405
|
+
source_distance_interp = temp_xds["SOURCE_DISTANCE"]
|
|
406
|
+
|
|
383
407
|
else:
|
|
384
|
-
|
|
385
|
-
temp_xds["
|
|
408
|
+
source_direction_interp = interpolate_to_time(
|
|
409
|
+
temp_xds["SOURCE_DIRECTION"],
|
|
410
|
+
interp_time,
|
|
411
|
+
"field_and_source_xds",
|
|
412
|
+
"time_ephemeris",
|
|
413
|
+
)
|
|
414
|
+
source_distance_interp = interpolate_to_time(
|
|
415
|
+
temp_xds["SOURCE_DISTANCE"],
|
|
386
416
|
interp_time,
|
|
387
417
|
"field_and_source_xds",
|
|
388
418
|
"time_ephemeris",
|
|
@@ -390,68 +420,38 @@ def extract_ephemeris_info(
|
|
|
390
420
|
|
|
391
421
|
xds = xr.merge([xds, temp_xds])
|
|
392
422
|
|
|
393
|
-
# Add the
|
|
394
|
-
# We also need to add a distance dimension to the FIELD_PHASE_CENTER or FIELD_REFERENCE_CENTER to match the
|
|
395
|
-
#
|
|
423
|
+
# Add the SOURCE_DIRECTION to the FIELD_PHASE_CENTER or FIELD_REFERENCE_CENTER. Ephemeris obs: When loaded from the MSv2 field table the FIELD_REFERENCE_CENTER or FIELD_PHASE_CENTER only contain an offset from the SOURCE_DIRECTION.
|
|
424
|
+
# We also need to add a distance dimension to the FIELD_PHASE_CENTER or FIELD_REFERENCE_CENTER to match the SOURCE_DIRECTION.
|
|
425
|
+
# FIELD_PHASE_CENTER_DIRECTION is used for interferometer data and FIELD_REFERENCE_CENTER_DIRECTION is used for single dish data.
|
|
396
426
|
if is_single_dish:
|
|
397
|
-
|
|
427
|
+
center_dir_dv = "FIELD_REFERENCE_CENTER_DIRECTION"
|
|
428
|
+
center_dis_dv = "FIELD_REFERENCE_CENTER_DISTANCE"
|
|
398
429
|
else:
|
|
399
|
-
|
|
430
|
+
center_dir_dv = "FIELD_PHASE_CENTER_DIRECTION"
|
|
431
|
+
center_dis_dv = "FIELD_PHASE_CENTER_DISTANCE"
|
|
400
432
|
|
|
401
433
|
xds = xds.sel(field_name=field_names) # Expand for all times in ms
|
|
402
434
|
xds = xds.assign_coords({"time": ("field_name", interp_time)})
|
|
403
435
|
xds["time"].attrs.update(standard_time_coord_attrs)
|
|
404
436
|
xds = xds.swap_dims({"field_name": "time"})
|
|
405
437
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
xds[center_dv].values + source_location_interp[:, 0:2].values
|
|
438
|
+
field_phase_center_direction = wrap_to_pi(
|
|
439
|
+
xds[center_dir_dv].values + source_direction_interp.values
|
|
409
440
|
)
|
|
410
441
|
|
|
411
|
-
|
|
412
|
-
|
|
442
|
+
xds[center_dir_dv] = xr.DataArray(
|
|
443
|
+
field_phase_center_direction,
|
|
444
|
+
dims=["time", "sky_dir_label"],
|
|
413
445
|
)
|
|
414
446
|
|
|
415
|
-
|
|
416
|
-
|
|
447
|
+
xds[center_dis_dv] = xr.DataArray(
|
|
448
|
+
source_distance_interp.values,
|
|
449
|
+
dims=["time", "sky_dis_label"],
|
|
417
450
|
)
|
|
418
451
|
|
|
419
|
-
xds[
|
|
420
|
-
field_phase_center,
|
|
421
|
-
dims=["time", "sky_pos_label"],
|
|
422
|
-
)
|
|
452
|
+
xds[center_dir_dv].attrs.update(xds["SOURCE_DIRECTION"].attrs)
|
|
423
453
|
|
|
424
|
-
|
|
425
|
-
# assert (
|
|
426
|
-
# interp_time is not None
|
|
427
|
-
# ), 'ephemeris_interpolate must be True if there is ephemeris data and multiple fields (this will occur if "FIELD_ID" is not in partition_scheme).'
|
|
428
|
-
|
|
429
|
-
# field_phase_center = wrap_to_pi(
|
|
430
|
-
# xds[center_dv].values + xds["SOURCE_LOCATION"][:, 0:2].values
|
|
431
|
-
# )
|
|
432
|
-
# field_phase_center = np.column_stack(
|
|
433
|
-
# (field_phase_center, np.zeros(xds[center_dv].values.shape[0]))
|
|
434
|
-
# )
|
|
435
|
-
# field_phase_center[:, -1] = (
|
|
436
|
-
# field_phase_center[:, -1] + xds["SOURCE_LOCATION"][:, -1].values
|
|
437
|
-
# )
|
|
438
|
-
|
|
439
|
-
# xds[center_dv] = xr.DataArray(
|
|
440
|
-
# field_phase_center,
|
|
441
|
-
# dims=[xds["SOURCE_LOCATION"].dims[0], "sky_pos_label"],
|
|
442
|
-
# )
|
|
443
|
-
# else:
|
|
444
|
-
# field_phase_center = (
|
|
445
|
-
# np.append(xds[center_dv].values, 0) + xds["SOURCE_LOCATION"].values
|
|
446
|
-
# )
|
|
447
|
-
# field_phase_center[:, 0:2] = wrap_to_pi(field_phase_center[:, 0:2])
|
|
448
|
-
|
|
449
|
-
# xds[center_dv] = xr.DataArray(
|
|
450
|
-
# field_phase_center,
|
|
451
|
-
# dims=[xds["SOURCE_LOCATION"].dims[0], "sky_pos_label"],
|
|
452
|
-
# )
|
|
453
|
-
|
|
454
|
-
xds[center_dv].attrs.update(xds["SOURCE_LOCATION"].attrs)
|
|
454
|
+
xds[center_dis_dv].attrs.update(xds["SOURCE_DISTANCE"].attrs)
|
|
455
455
|
|
|
456
456
|
return xds
|
|
457
457
|
|
|
@@ -573,7 +573,9 @@ def pad_missing_sources(
|
|
|
573
573
|
for missing_id in missing_source_ids:
|
|
574
574
|
missing_source_xds[concat_dim] = missing_id
|
|
575
575
|
xdss_to_concat.append(missing_source_xds)
|
|
576
|
-
filled_source_xds = xr.concat(xdss_to_concat, concat_dim).sortby(
|
|
576
|
+
filled_source_xds = xr.concat(xdss_to_concat, concat_dim, join="outer").sortby(
|
|
577
|
+
concat_dim
|
|
578
|
+
)
|
|
577
579
|
|
|
578
580
|
return filled_source_xds
|
|
579
581
|
|
|
@@ -611,7 +613,7 @@ def extract_source_info(
|
|
|
611
613
|
|
|
612
614
|
if all(source_id == -1):
|
|
613
615
|
logger.warning(
|
|
614
|
-
|
|
616
|
+
"Source_id is -1. No source information will be included in the field_and_source_xds."
|
|
615
617
|
)
|
|
616
618
|
xds = xds.assign_coords(
|
|
617
619
|
{"source_name": ("field_name", unknown)}
|
|
@@ -655,7 +657,7 @@ def extract_source_info(
|
|
|
655
657
|
# ), "Can only process source table with a single time entry for a source_id and spectral_window_id."
|
|
656
658
|
if len(source_xds.TIME) > len(unique_source_id):
|
|
657
659
|
logger.warning(
|
|
658
|
-
|
|
660
|
+
"Source table has more than one time entry for a source_id and spectral_window_id. This is not currently supported. Only the first time entry will be used."
|
|
659
661
|
)
|
|
660
662
|
source_xds = source_xds.drop_duplicates("SOURCE_ID", keep="first")
|
|
661
663
|
|
|
@@ -689,9 +691,6 @@ def extract_source_info(
|
|
|
689
691
|
# If ephemeris data is present we ignore the SOURCE_DIRECTION in the source table.
|
|
690
692
|
if not is_ephemeris:
|
|
691
693
|
direction_msv2_col = "DIRECTION"
|
|
692
|
-
msv4_measure = column_description_casacore_to_msv4_measure(
|
|
693
|
-
source_column_description[direction_msv2_col]
|
|
694
|
-
)
|
|
695
694
|
|
|
696
695
|
msv2_direction_dims = source_xds[direction_msv2_col].dims
|
|
697
696
|
if (
|
|
@@ -709,7 +708,7 @@ def extract_source_info(
|
|
|
709
708
|
location_msv4_measure = column_description_casacore_to_msv4_measure(
|
|
710
709
|
source_column_description[direction_msv2_col]
|
|
711
710
|
)
|
|
712
|
-
xds["
|
|
711
|
+
xds["SOURCE_DIRECTION"] = xr.DataArray(
|
|
713
712
|
direction_var.data, dims=direction_dims, attrs=location_msv4_measure
|
|
714
713
|
)
|
|
715
714
|
|
|
@@ -739,14 +738,15 @@ def extract_source_info(
|
|
|
739
738
|
|
|
740
739
|
# Need to add doppler info if present. Add check.
|
|
741
740
|
try:
|
|
742
|
-
|
|
741
|
+
load_generic_table(
|
|
743
742
|
path,
|
|
744
743
|
"DOPPLER",
|
|
745
744
|
)
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
745
|
+
logger.warning(
|
|
746
|
+
"Doppler table present. Please open an issue on "
|
|
747
|
+
"https://github.com/casangi/xradio/issues so that we can add support for this."
|
|
748
|
+
)
|
|
749
|
+
except ValueError:
|
|
750
750
|
pass
|
|
751
751
|
|
|
752
752
|
xds = xds.assign_coords(coords)
|
|
@@ -756,50 +756,6 @@ def extract_source_info(
|
|
|
756
756
|
return xds, np.sum(num_lines[unique_source_ids_indices])
|
|
757
757
|
|
|
758
758
|
|
|
759
|
-
def make_field_dims_and_coords(
|
|
760
|
-
field_xds: xr.Dataset, field_id: Union[int, np.ndarray], field_times: list
|
|
761
|
-
) -> tuple[list, dict]:
|
|
762
|
-
"""
|
|
763
|
-
Produces the dimensions and coordinates used in the field data variables
|
|
764
|
-
extracted from the MSv2 FIELD subtable (FIELD_PHASE_CENTER/
|
|
765
|
-
FIELD_REFERENCE_CENTER).
|
|
766
|
-
|
|
767
|
-
Parameters:
|
|
768
|
-
----------
|
|
769
|
-
field_xds: xr.Dataset
|
|
770
|
-
generic field xarray dataset
|
|
771
|
-
field_id: Union[int, np.ndarray]
|
|
772
|
-
field_id of the dataset
|
|
773
|
-
field_times:
|
|
774
|
-
Unique times for the dataset (when not partitioning by FIELD_ID)
|
|
775
|
-
|
|
776
|
-
Returns:
|
|
777
|
-
-------
|
|
778
|
-
tuple : tuple[list, dict]
|
|
779
|
-
The dimensions and coordinates to use with field data variables. The
|
|
780
|
-
dimensions are produced as a list of dimension names, and the
|
|
781
|
-
coordinates as a dict for xarray coords.
|
|
782
|
-
"""
|
|
783
|
-
|
|
784
|
-
coords = {"sky_dir_label": ["ra", "dec"]}
|
|
785
|
-
|
|
786
|
-
# field_times is the same as the time axis in the main MSv4 dataset and is used if more than one field is present.
|
|
787
|
-
if field_times is not None:
|
|
788
|
-
coords["time"] = field_times
|
|
789
|
-
dims = ["time", "sky_dir_label"]
|
|
790
|
-
coords["field_name"] = (
|
|
791
|
-
"time",
|
|
792
|
-
np.char.add(field_xds["NAME"].data, np.char.add("_", field_id.astype(str))),
|
|
793
|
-
)
|
|
794
|
-
# coords["field_id"] = ("time", field_id)
|
|
795
|
-
else:
|
|
796
|
-
coords["field_name"] = field_xds["NAME"].values.item() + "_" + str(field_id)
|
|
797
|
-
# coords["field_id"] = field_id
|
|
798
|
-
dims = ["field_name", "sky_dir_label"]
|
|
799
|
-
|
|
800
|
-
return dims, coords
|
|
801
|
-
|
|
802
|
-
|
|
803
759
|
def extract_field_info_and_check_ephemeris(
|
|
804
760
|
field_and_source_xds: xr.Dataset,
|
|
805
761
|
in_file: str,
|
|
@@ -892,14 +848,17 @@ def extract_field_info_and_check_ephemeris(
|
|
|
892
848
|
if is_single_dish:
|
|
893
849
|
to_new_data_variables = {
|
|
894
850
|
"REFERENCE_DIR": [
|
|
895
|
-
"
|
|
851
|
+
"FIELD_REFERENCE_CENTER_DIRECTION",
|
|
896
852
|
["field_name", "sky_dir_label"],
|
|
897
853
|
],
|
|
898
854
|
"FIELD_ID": ["FIELD_ID", ["field_name"]],
|
|
899
855
|
}
|
|
900
856
|
else:
|
|
901
857
|
to_new_data_variables = {
|
|
902
|
-
"PHASE_DIR": [
|
|
858
|
+
"PHASE_DIR": [
|
|
859
|
+
"FIELD_PHASE_CENTER_DIRECTION",
|
|
860
|
+
["field_name", "sky_dir_label"],
|
|
861
|
+
],
|
|
903
862
|
# "DELAY_DIR": ["FIELD_DELAY_CENTER",["field_name", "sky_dir_label"]],
|
|
904
863
|
# "REFERENCE_DIR": ["FIELD_REFERENCE_CENTER",["field_name", "sky_dir_label"]],
|
|
905
864
|
}
|
|
@@ -937,59 +896,6 @@ def extract_field_info_and_check_ephemeris(
|
|
|
937
896
|
# field_id shouldn ot be in final xds, and no longer needed past this point
|
|
938
897
|
field_and_source_xds = field_and_source_xds.drop_vars("field_id")
|
|
939
898
|
|
|
940
|
-
# dims, coords = make_field_dims_and_coords(field_xds, field_id, field_times)
|
|
941
|
-
|
|
942
|
-
# if is_single_dish:
|
|
943
|
-
# field_data_variables = {
|
|
944
|
-
# "REFERENCE_DIR": "FIELD_REFERENCE_CENTER",
|
|
945
|
-
# }
|
|
946
|
-
# else:
|
|
947
|
-
# field_data_variables = {
|
|
948
|
-
# # "DELAY_DIR": "FIELD_DELAY_CENTER",
|
|
949
|
-
# "PHASE_DIR": "FIELD_PHASE_CENTER",
|
|
950
|
-
# # "REFERENCE_DIR": "FIELD_REFERENCE_CENTER",
|
|
951
|
-
# }
|
|
952
|
-
|
|
953
|
-
# field_column_description = field_xds.attrs["other"]["msv2"]["ctds_attrs"][
|
|
954
|
-
# "column_descriptions"
|
|
955
|
-
# ]
|
|
956
|
-
|
|
957
|
-
# delay_dir_ref_col = "DelayDir_Ref"
|
|
958
|
-
# if field_xds.get(delay_dir_ref_col) is None:
|
|
959
|
-
# delaydir_ref = None
|
|
960
|
-
# else:
|
|
961
|
-
# delaydir_ref = check_if_consistent(
|
|
962
|
-
# field_xds.get(delay_dir_ref_col), delay_dir_ref_col
|
|
963
|
-
# )
|
|
964
|
-
|
|
965
|
-
# for generic_name, msv4_name in field_data_variables.items():
|
|
966
|
-
# msv4_measure = column_description_casacore_to_msv4_measure(
|
|
967
|
-
# field_column_description[generic_name], ref_code=delaydir_ref
|
|
968
|
-
# )
|
|
969
|
-
|
|
970
|
-
# print(msv4_name,generic_name,field_xds[generic_name].data.shape,field_xds[generic_name].data)
|
|
971
|
-
|
|
972
|
-
# field_and_source_xds[msv4_name] = xr.DataArray.from_dict(
|
|
973
|
-
# {
|
|
974
|
-
# "dims": dims,
|
|
975
|
-
# "data": list(field_xds[generic_name].data),
|
|
976
|
-
# "attrs": msv4_measure,
|
|
977
|
-
# }
|
|
978
|
-
# )
|
|
979
|
-
|
|
980
|
-
# field_measures_type = "sky_coord"
|
|
981
|
-
# field_and_source_xds[msv4_name].attrs["type"] = field_measures_type
|
|
982
|
-
|
|
983
|
-
# field_and_source_xds = field_and_source_xds.assign_coords(coords)
|
|
984
|
-
# if "time" in field_and_source_xds:
|
|
985
|
-
# time_column_description = field_xds.attrs["other"]["msv2"]["ctds_attrs"][
|
|
986
|
-
# "column_descriptions"
|
|
987
|
-
# ]["TIME"]
|
|
988
|
-
# time_msv4_measure = column_description_casacore_to_msv4_measure(
|
|
989
|
-
# time_column_description
|
|
990
|
-
# )
|
|
991
|
-
# field_and_source_xds.coords["time"].attrs.update(time_msv4_measure)
|
|
992
|
-
|
|
993
899
|
return (
|
|
994
900
|
field_and_source_xds,
|
|
995
901
|
ephemeris_path,
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import toolviper.utils.logger as logger
|
|
2
1
|
from xradio._utils.schema import column_description_casacore_to_msv4_measure
|
|
3
2
|
|
|
4
3
|
col_to_data_variable_names = {
|
|
@@ -39,6 +38,6 @@ def create_attribute_metadata(col, main_column_descriptions):
|
|
|
39
38
|
if col in ["DATA", "CORRECTED_DATA", "WEIGHT"]:
|
|
40
39
|
if not attrs_metadata:
|
|
41
40
|
attrs_metadata["type"] = "quanta"
|
|
42
|
-
attrs_metadata["units"] =
|
|
41
|
+
attrs_metadata["units"] = "unkown"
|
|
43
42
|
|
|
44
43
|
return attrs_metadata
|
|
@@ -10,7 +10,7 @@ import toolviper.utils.logger as logger
|
|
|
10
10
|
|
|
11
11
|
from .subtables import subt_rename_ids
|
|
12
12
|
from ._tables.read import load_generic_table, convert_casacore_time
|
|
13
|
-
from xradio._utils.list_and_array import check_if_consistent
|
|
13
|
+
from xradio._utils.list_and_array import check_if_consistent
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
def create_info_dicts(
|
|
@@ -47,12 +47,13 @@ def create_info_dicts(
|
|
|
47
47
|
info dicts ready to be used to update the attrs of the MSv4
|
|
48
48
|
"""
|
|
49
49
|
|
|
50
|
-
if "line_name" in field_and_source_xds.coords:
|
|
51
|
-
line_name = to_list(unique_1d(np.ravel(field_and_source_xds.line_name.values)))
|
|
52
|
-
else:
|
|
53
|
-
line_name = []
|
|
54
|
-
|
|
55
50
|
info_dicts = {}
|
|
51
|
+
|
|
52
|
+
# if "line_name" in field_and_source_xds.coords:
|
|
53
|
+
# line_name = to_list(unique_1d(np.ravel(field_and_source_xds.line_name.values)))
|
|
54
|
+
# else:
|
|
55
|
+
# line_name = []
|
|
56
|
+
|
|
56
57
|
# info_dicts["partition_info"] = {
|
|
57
58
|
# # "spectral_window_id": xds.frequency.attrs["spectral_window_id"],
|
|
58
59
|
# "spectral_window_name": xds.frequency.attrs["spectral_window_name"],
|
|
@@ -125,7 +126,7 @@ def create_observation_info(in_file: str, observation_id: int):
|
|
|
125
126
|
exec_block_xds = load_generic_table(in_file, "ASDM_EXECBLOCK")
|
|
126
127
|
except ValueError as exc:
|
|
127
128
|
logger.debug(
|
|
128
|
-
"Did not find the ASDM_EXECBLOCK subtable, not loading optional fields in observation_info"
|
|
129
|
+
f"Did not find the ASDM_EXECBLOCK subtable, not loading optional fields in observation_info. Exception: {exc}"
|
|
129
130
|
)
|
|
130
131
|
if exec_block_xds:
|
|
131
132
|
exec_block_info = extract_exec_block_info(exec_block_xds)
|