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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. xradio/{vis → correlated_data}/__init__.py +3 -2
  2. xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/_tables/load_main_table.py +1 -1
  3. xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/_tables/read.py +14 -0
  4. xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/conversion.py +117 -58
  5. xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/create_antenna_xds.py +195 -167
  6. xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/create_field_and_source_xds.py +40 -39
  7. xradio/correlated_data/_utils/_ms/msv4_info_dicts.py +203 -0
  8. xradio/correlated_data/_utils/_ms/msv4_sub_xdss.py +516 -0
  9. xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/subtables.py +1 -1
  10. xradio/{vis/_vis_utils → correlated_data/_utils}/zarr.py +3 -3
  11. xradio/{vis → correlated_data}/convert_msv2_to_processing_set.py +9 -2
  12. xradio/correlated_data/correlated_xds.py +13 -0
  13. xradio/{vis → correlated_data}/load_processing_set.py +13 -17
  14. xradio/{vis/read_processing_set.py → correlated_data/open_processing_set.py} +20 -22
  15. xradio/{vis/_processing_set.py → correlated_data/processing_set.py} +11 -12
  16. xradio/{vis → correlated_data}/schema.py +572 -186
  17. xradio/correlated_data/test__processing_set.py +74 -0
  18. {xradio-0.0.40.dist-info → xradio-0.0.41.dist-info}/METADATA +9 -10
  19. xradio-0.0.41.dist-info/RECORD +75 -0
  20. {xradio-0.0.40.dist-info → xradio-0.0.41.dist-info}/WHEEL +1 -1
  21. xradio/vis/_vis_utils/_ms/msv4_infos.py +0 -0
  22. xradio/vis/_vis_utils/_ms/msv4_sub_xdss.py +0 -306
  23. xradio-0.0.40.dist-info/RECORD +0 -73
  24. /xradio/{vis/_vis_utils → correlated_data/_utils}/__init__.py +0 -0
  25. /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/_tables/load.py +0 -0
  26. /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/_tables/read_main_table.py +0 -0
  27. /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/_tables/read_subtables.py +0 -0
  28. /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/_tables/table_query.py +0 -0
  29. /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/_tables/write.py +0 -0
  30. /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/_tables/write_exp_api.py +0 -0
  31. /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/chunks.py +0 -0
  32. /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/descr.py +0 -0
  33. /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/msv2_msv3.py +0 -0
  34. /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/msv2_to_msv4_meta.py +0 -0
  35. /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/optimised_functions.py +0 -0
  36. /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/partition_queries.py +0 -0
  37. /xradio/{vis/_vis_utils → correlated_data/_utils}/_ms/partitions.py +0 -0
  38. /xradio/{vis/_vis_utils → correlated_data/_utils}/_utils/cds.py +0 -0
  39. /xradio/{vis/_vis_utils → correlated_data/_utils}/_utils/partition_attrs.py +0 -0
  40. /xradio/{vis/_vis_utils → correlated_data/_utils}/_utils/stokes_types.py +0 -0
  41. /xradio/{vis/_vis_utils → correlated_data/_utils}/_utils/xds_helper.py +0 -0
  42. /xradio/{vis/_vis_utils → correlated_data/_utils}/_zarr/encoding.py +0 -0
  43. /xradio/{vis/_vis_utils → correlated_data/_utils}/_zarr/read.py +0 -0
  44. /xradio/{vis/_vis_utils → correlated_data/_utils}/_zarr/write.py +0 -0
  45. /xradio/{vis/_vis_utils → correlated_data/_utils}/ms.py +0 -0
  46. {xradio-0.0.40.dist-info → xradio-0.0.41.dist-info}/LICENSE.txt +0 -0
  47. {xradio-0.0.40.dist-info → xradio-0.0.41.dist-info}/top_level.txt +0 -0
@@ -6,14 +6,16 @@ import numpy as np
6
6
  import xarray as xr
7
7
  import os
8
8
 
9
- from xradio.vis._vis_utils._ms.subtables import subt_rename_ids
10
- from xradio.vis._vis_utils._ms._tables.read import (
9
+ from xradio.correlated_data._utils._ms.subtables import subt_rename_ids
10
+ from xradio.correlated_data._utils._ms._tables.read import (
11
11
  load_generic_table,
12
+ convert_casacore_time,
12
13
  convert_casacore_time_to_mjd,
13
14
  make_taql_where_between_min_max,
15
+ table_exists,
14
16
  )
15
17
  from xradio._utils.schema import convert_generic_xds_to_xradio_schema
16
- from xradio.vis._vis_utils._ms.msv4_sub_xdss import interpolate_to_time
18
+ from xradio.correlated_data._utils._ms.msv4_sub_xdss import interpolate_to_time
17
19
 
18
20
  from xradio._utils.list_and_array import (
19
21
  check_if_consistent,
@@ -29,8 +31,6 @@ def create_antenna_xds(
29
31
  antenna_id: list,
30
32
  feed_id: list,
31
33
  telescope_name: str,
32
- time_min_max: Tuple[np.float64, np.float64],
33
- phase_cal_interp_time: Union[xr.DataArray, None] = None,
34
34
  ) -> xr.Dataset:
35
35
  """
36
36
  Create an Xarray Dataset containing antenna information.
@@ -47,10 +47,6 @@ def create_antenna_xds(
47
47
  List of feed IDs.
48
48
  telescope_name : str
49
49
  Name of the telescope.
50
- time_min_max : Tuple[np.float46, np.float64]
51
- Min / max times to constrain loading (usually to the time range relevant to an MSv4)
52
- phase_cal_interp_time : Union[xr.DataArray, None]
53
- Time axis to interpolate the data vars to (usually main MSv4 time)
54
50
 
55
51
  Returns
56
52
  ----------
@@ -64,13 +60,6 @@ def create_antenna_xds(
64
60
  ant_xds, in_file, antenna_id, feed_id, spectral_window_id
65
61
  )
66
62
 
67
- ant_xds = extract_phase_cal_info(
68
- ant_xds, in_file, spectral_window_id, time_min_max, phase_cal_interp_time
69
- ) # Only used in VLBI.
70
- ant_xds = extract_gain_curve_info(
71
- ant_xds, in_file, spectral_window_id
72
- ) # Only used in VLBI.
73
-
74
63
  ant_xds.attrs["overall_telescope_name"] = telescope_name
75
64
  return ant_xds
76
65
 
@@ -164,6 +153,15 @@ def extract_antenna_info(
164
153
  else:
165
154
  ant_xds.attrs["relocatable_antennas"] = False
166
155
 
156
+ ant_xds = ant_xds.assign_coords(
157
+ {
158
+ "telescope_name": (
159
+ "antenna_name",
160
+ np.array([telescope_name for ant in ant_xds["antenna_name"]]),
161
+ )
162
+ }
163
+ )
164
+
167
165
  return ant_xds
168
166
 
169
167
 
@@ -277,103 +275,122 @@ def extract_feed_info(
277
275
  return ant_xds
278
276
 
279
277
 
280
- def extract_gain_curve_info(
281
- ant_xds: xr.Dataset, in_file: str, spectral_window_id: int
278
+ def create_gain_curve_xds(
279
+ in_file: str, spectral_window_id: int, ant_xds: xr.Dataset
282
280
  ) -> xr.Dataset:
283
281
  """
284
- Reformats MSv2 GAIN CURVE table content to MSv4 schema.
282
+ Produces a gain_curve_xds, reformats MSv2 GAIN CURVE table content to MSv4 schema.
285
283
 
286
284
  Parameters
287
285
  ----------
288
- ant_xds : xr.Dataset
289
- The dataset that will be updated with gain curve information.
290
286
  in_file : str
291
287
  Path to the input MSv2.
292
288
  spectral_window_id : int
293
289
  The ID of the spectral window.
290
+ ant_xds : xr.Dataset
291
+ The antenna_xds that has information such as names, stations, etc., for coordinates
294
292
 
295
293
  Returns
296
294
  -------
297
295
  xr.Dataset
298
296
  The updated antenna dataset with gain curve information.
299
297
  """
300
- if os.path.exists(
301
- os.path.join(in_file, "GAIN_CURVE")
302
- ): # Check if the table exists.
303
- generic_gain_curve_xds = load_generic_table(
304
- in_file,
298
+
299
+ gain_curve_xds = None
300
+ if not table_exists(os.path.join(in_file, "GAIN_CURVE")):
301
+ return gain_curve_xds
302
+
303
+ generic_gain_curve_xds = load_generic_table(
304
+ in_file,
305
+ "GAIN_CURVE",
306
+ taql_where=f" where (ANTENNA_ID IN [{','.join(map(str,ant_xds.antenna_id.values))}]) AND (SPECTRAL_WINDOW_ID = {spectral_window_id})",
307
+ )
308
+
309
+ if not generic_gain_curve_xds.data_vars:
310
+ # Some times the gain_curve table is empty (this is the case with ngEHT simulation data we have).
311
+ return gain_curve_xds
312
+
313
+ assert (
314
+ len(generic_gain_curve_xds.SPECTRAL_WINDOW_ID) == 1
315
+ ), "Only one spectral window is supported."
316
+ generic_gain_curve_xds = generic_gain_curve_xds.isel(
317
+ SPECTRAL_WINDOW_ID=0, drop=True
318
+ ) # Drop the spectral window dimension as it is singleton.
319
+
320
+ assert (
321
+ len(generic_gain_curve_xds.TIME) == 1
322
+ ), "Only one gain curve measurement per antenna is supported."
323
+ measured_time = generic_gain_curve_xds.coords["TIME"].values[0]
324
+ generic_gain_curve_xds = generic_gain_curve_xds.isel(TIME=0, drop=True)
325
+
326
+ generic_gain_curve_xds = generic_gain_curve_xds.sel(
327
+ ANTENNA_ID=ant_xds.antenna_id, drop=False
328
+ ) # Make sure the antenna_id is in the same order as the xds .
329
+
330
+ gain_curve_xds = xr.Dataset(attrs={"type": "gain_curve"})
331
+
332
+ to_new_data_variables = {
333
+ "INTERVAL": ["GAIN_CURVE_INTERVAL", ["antenna_name"]],
334
+ "GAIN": [
305
335
  "GAIN_CURVE",
306
- taql_where=f" where (ANTENNA_ID IN [{','.join(map(str,ant_xds.antenna_id.values))}]) AND (SPECTRAL_WINDOW_ID = {spectral_window_id})",
307
- )
336
+ ["antenna_name", "poly_term", "receptor_label"],
337
+ ],
338
+ "SENSITIVITY": [
339
+ "GAIN_CURVE_SENSITIVITY",
340
+ ["antenna_name", "receptor_label"],
341
+ ],
342
+ }
308
343
 
309
- if (
310
- generic_gain_curve_xds.data_vars
311
- ): # Some times the gain_curve table is empty (this is the case with ngEHT simulation data we have).
312
-
313
- assert (
314
- len(generic_gain_curve_xds.SPECTRAL_WINDOW_ID) == 1
315
- ), "Only one spectral window is supported."
316
- generic_gain_curve_xds = generic_gain_curve_xds.isel(
317
- SPECTRAL_WINDOW_ID=0, drop=True
318
- ) # Drop the spectral window dimension as it is singleton.
319
-
320
- assert (
321
- len(generic_gain_curve_xds.TIME) == 1
322
- ), "Only one gain curve measurement per antenna is supported."
323
- generic_gain_curve_xds = generic_gain_curve_xds.isel(TIME=0, drop=True)
324
-
325
- generic_gain_curve_xds = generic_gain_curve_xds.sel(
326
- ANTENNA_ID=ant_xds.antenna_id, drop=False
327
- ) # Make sure the antenna_id is in the same order as the xds .
328
-
329
- to_new_data_variables = {
330
- "INTERVAL": ["GAIN_CURVE_INTERVAL", ["antenna_name"]],
331
- "GAIN": [
332
- "GAIN_CURVE",
333
- ["antenna_name", "poly_term", "receptor_label"],
334
- ],
335
- "SENSITIVITY": [
336
- "GAIN_CURVE_SENSITIVITY",
337
- ["antenna_name", "receptor_label"],
338
- ],
339
- }
340
-
341
- to_new_coords = {
342
- "TYPE": ["gain_curve_type", ["antenna_name"]],
343
- }
344
-
345
- # print(generic_gain_curve_xds)
346
-
347
- ant_xds = convert_generic_xds_to_xradio_schema(
348
- generic_gain_curve_xds,
349
- ant_xds,
350
- to_new_data_variables,
351
- to_new_coords,
352
- )
353
- ant_xds["GAIN_CURVE"] = ant_xds["GAIN_CURVE"].transpose(
354
- "antenna_name", "receptor_label", "poly_term"
355
- )
344
+ to_new_coords = {
345
+ "TYPE": ["gain_curve_type", ["antenna_name"]],
346
+ }
356
347
 
357
- return ant_xds
348
+ gain_curve_xds = convert_generic_xds_to_xradio_schema(
349
+ generic_gain_curve_xds,
350
+ gain_curve_xds,
351
+ to_new_data_variables,
352
+ to_new_coords,
353
+ )
358
354
 
359
- else:
360
- return ant_xds
355
+ ant_borrowed_coords = {
356
+ "antenna_name": ant_xds.coords["antenna_name"],
357
+ "station": ant_xds.coords["station"],
358
+ "mount": ant_xds.coords["mount"],
359
+ "telescope_name": ant_xds.coords["telescope_name"],
360
+ "receptor_label": ant_xds.coords["receptor_label"],
361
+ "polarization_type": ant_xds.coords["polarization_type"],
362
+ }
363
+ gain_curve_xds = gain_curve_xds.assign_coords(ant_borrowed_coords)
364
+
365
+ gain_curve_xds.attrs.update(
366
+ {
367
+ "measured_date": np.datetime_as_string(
368
+ convert_casacore_time([measured_time])[0]
369
+ )
370
+ }
371
+ )
361
372
 
373
+ return gain_curve_xds
362
374
 
363
- def extract_phase_cal_info(
364
- ant_xds, path, spectral_window_id, time_min_max, phase_cal_interp_time
365
- ):
375
+
376
+ def create_phase_calibration_xds(
377
+ in_file: str,
378
+ spectral_window_id: int,
379
+ ant_xds: xr.Dataset,
380
+ time_min_max: Tuple[np.float64, np.float64],
381
+ phase_cal_interp_time: Union[xr.DataArray, None] = None,
382
+ ) -> xr.Dataset:
366
383
  """
367
- Reformats MSv2 Phase Cal table content to MSv4 schema.
384
+ Produces a phase_calibration_xds, reformats MSv2 Phase Cal table content to MSv4 schema.
368
385
 
369
386
  Parameters
370
387
  ----------
371
- ant_xds : xr.Dataset
372
- The dataset that will be updated with phase cal information.
373
388
  in_file : str
374
389
  Path to the input MSv2.
375
390
  spectral_window_id : int
376
391
  The ID of the spectral window.
392
+ ant_xds : xr.Dataset
393
+ The antenna_xds that has information such as names, stations, etc., for coordinates
377
394
  time_min_max : Tuple[np.float46, np.float64]
378
395
  Min / max times to constrain loading (usually to the time range relevant to an MSv4)
379
396
  interp_time : Union[xr.DataArray, None]
@@ -385,98 +402,109 @@ def extract_phase_cal_info(
385
402
  The updated antenna dataset with phase cal information.
386
403
  """
387
404
 
388
- if os.path.exists(os.path.join(path, "PHASE_CAL")):
405
+ phase_cal_xds = None
406
+ if not table_exists(os.path.join(in_file, "PHASE_CAL")):
407
+ return phase_cal_xds
389
408
 
390
- # Only read data between the min and max times of the visibility data in the MSv4.
391
- taql_time_range = make_taql_where_between_min_max(
392
- time_min_max, path, "PHASE_CAL", "TIME"
393
- )
394
- generic_phase_cal_xds = load_generic_table(
395
- path,
396
- "PHASE_CAL",
397
- timecols=["TIME"],
398
- taql_where=f" {taql_time_range} AND (ANTENNA_ID IN [{','.join(map(str,ant_xds.antenna_id.values))}]) AND (SPECTRAL_WINDOW_ID = {spectral_window_id})",
399
- )
409
+ # Only read data between the min and max times of the visibility data in the MSv4.
410
+ taql_time_range = make_taql_where_between_min_max(
411
+ time_min_max, in_file, "PHASE_CAL", "TIME"
412
+ )
413
+ generic_phase_cal_xds = load_generic_table(
414
+ in_file,
415
+ "PHASE_CAL",
416
+ timecols=["TIME"],
417
+ taql_where=f" {taql_time_range} AND (ANTENNA_ID IN [{','.join(map(str,ant_xds.antenna_id.values))}]) AND (SPECTRAL_WINDOW_ID = {spectral_window_id})",
418
+ )
400
419
 
401
- assert (
402
- len(generic_phase_cal_xds.SPECTRAL_WINDOW_ID) == 1
403
- ), "Only one spectral window is supported."
404
- generic_phase_cal_xds = generic_phase_cal_xds.isel(
405
- SPECTRAL_WINDOW_ID=0, drop=True
406
- ) # Drop the spectral window dimension as it is singleton.
407
-
408
- generic_phase_cal_xds = generic_phase_cal_xds.sel(
409
- ANTENNA_ID=ant_xds.antenna_id, drop=False
410
- ) # Make sure the antenna_id is in the same order as the xds.
411
-
412
- to_new_data_variables = {
413
- "INTERVAL": ["PHASE_CAL_INTERVAL", ["antenna_name", "time_phase_cal"]],
414
- "TONE_FREQUENCY": [
415
- "PHASE_CAL_TONE_FREQUENCY",
416
- ["antenna_name", "time_phase_cal", "tone_label", "receptor_label"],
417
- ],
418
- "PHASE_CAL": [
419
- "PHASE_CAL",
420
- ["antenna_name", "time_phase_cal", "tone_label", "receptor_label"],
421
- ],
422
- "CABLE_CAL": ["PHASE_CAL_CABLE_CAL", ["antenna_name", "time_phase_cal"]],
423
- }
420
+ assert (
421
+ len(generic_phase_cal_xds.SPECTRAL_WINDOW_ID) == 1
422
+ ), "Only one spectral window is supported."
423
+ generic_phase_cal_xds = generic_phase_cal_xds.isel(
424
+ SPECTRAL_WINDOW_ID=0, drop=True
425
+ ) # Drop the spectral window dimension as it is singleton.
426
+
427
+ generic_phase_cal_xds = generic_phase_cal_xds.sel(
428
+ ANTENNA_ID=ant_xds.antenna_id, drop=False
429
+ ) # Make sure the antenna_id is in the same order as the xds.
424
430
 
425
- to_new_coords = {
426
- "TIME": ["time_phase_cal", ["time_phase_cal"]],
427
- }
431
+ to_new_data_variables = {
432
+ "INTERVAL": ["PHASE_CAL_INTERVAL", ["antenna_name", "time_phase_cal"]],
433
+ "TONE_FREQUENCY": [
434
+ "PHASE_CAL_TONE_FREQUENCY",
435
+ ["antenna_name", "time_phase_cal", "tone_label", "receptor_label"],
436
+ ],
437
+ "PHASE_CAL": [
438
+ "PHASE_CAL",
439
+ ["antenna_name", "time_phase_cal", "tone_label", "receptor_label"],
440
+ ],
441
+ "CABLE_CAL": ["PHASE_CAL_CABLE_CAL", ["antenna_name", "time_phase_cal"]],
442
+ }
428
443
 
429
- ant_xds = convert_generic_xds_to_xradio_schema(
430
- generic_phase_cal_xds, ant_xds, to_new_data_variables, to_new_coords
431
- )
432
- ant_xds["PHASE_CAL"] = ant_xds["PHASE_CAL"].transpose(
433
- "antenna_name", "time_phase_cal", "receptor_label", "tone_label"
434
- )
444
+ to_new_coords = {
445
+ "TIME": ["time_phase_cal", ["time_phase_cal"]],
446
+ }
435
447
 
436
- ant_xds["PHASE_CAL_TONE_FREQUENCY"] = ant_xds[
437
- "PHASE_CAL_TONE_FREQUENCY"
438
- ].transpose("antenna_name", "time_phase_cal", "receptor_label", "tone_label")
439
-
440
- # ant_xds = ant_xds.assign_coords({"tone_label" : "freq_" + np.arange(ant_xds.sizes["tone_label"]).astype(str)}) #Works on laptop but fails in github test runner.
441
- ant_xds = ant_xds.assign_coords(
442
- {
443
- "tone_label": np.array(
444
- list(
445
- map(
446
- lambda x, y: x + "_" + y,
447
- ["freq"] * ant_xds.sizes["tone_label"],
448
- np.arange(ant_xds.sizes["tone_label"]).astype(str),
449
- )
450
- )
451
- )
452
- }
453
- )
448
+ phase_cal_xds = xr.Dataset(attrs={"type": "phase_cal"})
449
+ phase_cal_xds = convert_generic_xds_to_xradio_schema(
450
+ generic_phase_cal_xds, phase_cal_xds, to_new_data_variables, to_new_coords
451
+ )
454
452
 
455
- ant_xds["time_phase_cal"] = (
456
- ant_xds.time_phase_cal.astype("float64").astype("float64") / 10**9
453
+ phase_cal_xds["PHASE_CAL"] = phase_cal_xds["PHASE_CAL"].transpose(
454
+ "antenna_name", "time_phase_cal", "receptor_label", "tone_label"
455
+ )
456
+ phase_cal_xds["PHASE_CAL_TONE_FREQUENCY"] = phase_cal_xds[
457
+ "PHASE_CAL_TONE_FREQUENCY"
458
+ ].transpose("antenna_name", "time_phase_cal", "receptor_label", "tone_label")
459
+
460
+ ant_borrowed_coords = {
461
+ "antenna_name": ant_xds.coords["antenna_name"],
462
+ "station": ant_xds.coords["station"],
463
+ "mount": ant_xds.coords["mount"],
464
+ "telescope_name": ant_xds.coords["telescope_name"],
465
+ "receptor_label": ant_xds.coords["receptor_label"],
466
+ "polarization_type": ant_xds.coords["polarization_type"],
467
+ }
468
+ # phase_cal_xds = phase_cal_xds.assign_coords({"tone_label" : "freq_" + np.arange(phase_cal_xds.sizes["tone_label"]).astype(str)}) #Works on laptop but fails in github test runner.
469
+ tone_label_coord = {
470
+ "tone_label": np.array(
471
+ list(
472
+ map(
473
+ lambda x, y: x + "_" + y,
474
+ ["freq"] * phase_cal_xds.sizes["tone_label"],
475
+ np.arange(phase_cal_xds.sizes["tone_label"]).astype(str),
476
+ )
477
+ )
457
478
  )
479
+ }
480
+ phase_cal_xds = phase_cal_xds.assign_coords(ant_borrowed_coords | tone_label_coord)
458
481
 
459
- ant_xds = interpolate_to_time(
460
- ant_xds, phase_cal_interp_time, "antenna_xds", time_name="time_phase_cal"
461
- )
482
+ # Adjust expected types
483
+ phase_cal_xds["time_phase_cal"] = (
484
+ phase_cal_xds.time_phase_cal.astype("float64").astype("float64") / 10**9
485
+ )
462
486
 
463
- time_coord_attrs = {
464
- "type": "time",
465
- "units": ["s"],
466
- "scale": "UTC",
467
- "format": "UNIX",
468
- }
487
+ phase_cal_xds = interpolate_to_time(
488
+ phase_cal_xds,
489
+ phase_cal_interp_time,
490
+ "antenna_xds",
491
+ time_name="time_phase_cal",
492
+ )
469
493
 
470
- # If we interpolate rename the time_ephemeris_axis axis to time.
471
- if phase_cal_interp_time is not None:
472
- time_coord = {"time": ("time_phase_cal", phase_cal_interp_time.data)}
473
- ant_xds = ant_xds.assign_coords(time_coord)
474
- ant_xds.coords["time"].attrs.update(time_coord_attrs)
475
- ant_xds = ant_xds.swap_dims({"time_phase_cal": "time"}).drop_vars(
476
- "time_phase_cal"
477
- )
494
+ time_coord_attrs = {
495
+ "type": "time",
496
+ "units": ["s"],
497
+ "scale": "UTC",
498
+ "format": "UNIX",
499
+ }
478
500
 
479
- return ant_xds
501
+ # If we interpolate rename the time_phase_cal axis to time.
502
+ if phase_cal_interp_time is not None:
503
+ time_coord = {"time": ("time_phase_cal", phase_cal_interp_time.data)}
504
+ phase_cal_xds = phase_cal_xds.assign_coords(time_coord)
505
+ phase_cal_xds.coords["time"].attrs.update(time_coord_attrs)
506
+ phase_cal_xds = phase_cal_xds.swap_dims({"time_phase_cal": "time"}).drop_vars(
507
+ "time_phase_cal"
508
+ )
480
509
 
481
- else:
482
- return ant_xds
510
+ return phase_cal_xds
@@ -6,9 +6,9 @@ import numpy as np
6
6
  import xarray as xr
7
7
 
8
8
  import toolviper.utils.logger as logger
9
- from xradio.vis._vis_utils._ms.msv4_sub_xdss import interpolate_to_time
10
- from xradio.vis._vis_utils._ms.subtables import subt_rename_ids
11
- from xradio.vis._vis_utils._ms._tables.read import (
9
+ from xradio.correlated_data._utils._ms.msv4_sub_xdss import interpolate_to_time
10
+ from xradio.correlated_data._utils._ms.subtables import subt_rename_ids
11
+ from xradio.correlated_data._utils._ms._tables.read import (
12
12
  convert_casacore_time_to_mjd,
13
13
  make_taql_where_between_min_max,
14
14
  load_generic_table,
@@ -160,7 +160,7 @@ def extract_ephemeris_info(
160
160
 
161
161
  # Get meta data.
162
162
  ephemeris_meta = ephemeris_xds.attrs["other"]["msv2"]["ctds_attrs"]
163
- ephemris_column_description = ephemeris_xds.attrs["other"]["msv2"]["ctds_attrs"][
163
+ ephemeris_column_description = ephemeris_xds.attrs["other"]["msv2"]["ctds_attrs"][
164
164
  "column_descriptions"
165
165
  ]
166
166
 
@@ -174,27 +174,27 @@ def extract_ephemeris_info(
174
174
  sky_coord_frame = "ICRS" # We will have to just assume this.
175
175
 
176
176
  # Find out witch keyword is used for units (UNIT/QuantumUnits)
177
- if "UNIT" in ephemris_column_description["RA"]["keywords"]:
177
+ if "UNIT" in ephemeris_column_description["RA"]["keywords"]:
178
178
  unit_keyword = "UNIT"
179
179
  else:
180
180
  unit_keyword = "QuantumUnits"
181
181
 
182
182
  temp_xds = xr.Dataset()
183
183
 
184
- # Add mandatory data: OBSERVATION_POSITION
185
- observation_position = [
184
+ # Add mandatory data: OBSERVER_POSITION
185
+ observer_position = [
186
186
  ephemeris_meta["GeoLong"],
187
187
  ephemeris_meta["GeoLat"],
188
188
  ephemeris_meta["GeoDist"],
189
189
  ]
190
- temp_xds["OBSERVATION_POSITION"] = xr.DataArray(
191
- observation_position, dims=["ellipsoid_pos_label"]
190
+ temp_xds["OBSERVER_POSITION"] = xr.DataArray(
191
+ observer_position, dims=["ellipsoid_pos_label"]
192
192
  )
193
- temp_xds["OBSERVATION_POSITION"].attrs.update(
193
+ temp_xds["OBSERVER_POSITION"].attrs.update(
194
194
  {
195
195
  "type": "location",
196
196
  "units": ["deg", "deg", "m"],
197
- "data": observation_position,
197
+ "data": observer_position,
198
198
  "ellipsoid": "WGS84",
199
199
  "origin_object_name": "Earth",
200
200
  "coordinate_system": ephemeris_meta["obsloc"].lower(),
@@ -210,13 +210,13 @@ def extract_ephemeris_info(
210
210
  ephemeris_xds["Rho"].data,
211
211
  )
212
212
  ),
213
- dims=["time_ephemeris_axis", "sky_pos_label"],
213
+ dims=["time_ephemeris", "sky_pos_label"],
214
214
  )
215
215
  # Have to use cast_to_str because the ephemeris table units are not consistently in a list or a string.
216
216
  sky_coord_units = [
217
- cast_to_str(ephemris_column_description["RA"]["keywords"][unit_keyword]),
218
- cast_to_str(ephemris_column_description["DEC"]["keywords"][unit_keyword]),
219
- cast_to_str(ephemris_column_description["Rho"]["keywords"][unit_keyword]),
217
+ cast_to_str(ephemeris_column_description["RA"]["keywords"][unit_keyword]),
218
+ cast_to_str(ephemeris_column_description["DEC"]["keywords"][unit_keyword]),
219
+ cast_to_str(ephemeris_column_description["Rho"]["keywords"][unit_keyword]),
220
220
  ]
221
221
  temp_xds["SOURCE_LOCATION"].attrs.update(
222
222
  {"type": "sky_coord", "frame": sky_coord_frame, "units": sky_coord_units}
@@ -227,16 +227,17 @@ def extract_ephemeris_info(
227
227
  # Metadata has to be fixed manually. Alternatively, issues like
228
228
  # UNIT/QuantumUnits issue could be handled in convert_generic_xds_to_xradio_schema,
229
229
  # but for now preferring not to pollute that function.
230
+ time_ephemeris_dim = ["time_ephemeris"]
230
231
  to_new_data_variables = {
231
232
  # mandatory: SOURCE_RADIAL_VELOCITY
232
- "RadVel": ["SOURCE_RADIAL_VELOCITY", ["time_ephemeris_axis"]],
233
+ "RadVel": ["SOURCE_RADIAL_VELOCITY", time_ephemeris_dim],
233
234
  # optional: data NORTH_POLE_POSITION_ANGLE and NORTH_POLE_ANGULAR_DISTANCE
234
- "NP_ang": ["NORTH_POLE_POSITION_ANGLE", ["time_ephemeris_axis"]],
235
- "NP_dist": ["NORTH_POLE_ANGULAR_DISTANCE", ["time_ephemeris_axis"]],
235
+ "NP_ang": ["NORTH_POLE_POSITION_ANGLE", time_ephemeris_dim],
236
+ "NP_dist": ["NORTH_POLE_ANGULAR_DISTANCE", time_ephemeris_dim],
236
237
  # optional: HELIOCENTRIC_RADIAL_VELOCITY
237
- "rdot": ["HELIOCENTRIC_RADIAL_VELOCITY", ["time_ephemeris_axis"]],
238
+ "rdot": ["HELIOCENTRIC_RADIAL_VELOCITY", time_ephemeris_dim],
238
239
  # optional: OBSERVER_PHASE_ANGLE
239
- "phang": ["OBSERVER_PHASE_ANGLE", ["time_ephemeris_axis"]],
240
+ "phang": ["OBSERVER_PHASE_ANGLE", time_ephemeris_dim],
240
241
  }
241
242
  convert_generic_xds_to_xradio_schema(
242
243
  ephemeris_xds, temp_xds, to_new_data_variables, {}
@@ -251,7 +252,7 @@ def extract_ephemeris_info(
251
252
  "type": "quantity",
252
253
  "units": [
253
254
  cast_to_str(
254
- ephemris_column_description[generic_var_name]["keywords"][
255
+ ephemeris_column_description[generic_var_name]["keywords"][
255
256
  unit_keyword
256
257
  ]
257
258
  )
@@ -260,7 +261,7 @@ def extract_ephemeris_info(
260
261
  )
261
262
 
262
263
  # Add optional data: SUB_OBSERVER_POSITION and SUB_SOLAR_POSITION
263
- if "DiskLong" in ephemris_column_description:
264
+ if "DiskLong" in ephemeris_column_description:
264
265
  key_lon = "DiskLong"
265
266
  key_lat = "DiskLat"
266
267
  else:
@@ -268,7 +269,7 @@ def extract_ephemeris_info(
268
269
  key_lat = "diskLat"
269
270
 
270
271
  if key_lon in ephemeris_xds.data_vars:
271
- temp_xds["SUB_OBSERVER_POSITION"] = xr.DataArray(
272
+ temp_xds["SUB_OBSERVER_DIRECTION"] = xr.DataArray(
272
273
  np.column_stack(
273
274
  (
274
275
  ephemeris_xds[key_lon].data,
@@ -276,10 +277,10 @@ def extract_ephemeris_info(
276
277
  np.zeros(ephemeris_xds[key_lon].shape),
277
278
  )
278
279
  ),
279
- dims=["time_ephemeris_axis", "ellipsoid_pos_label"],
280
+ dims=["time_ephemeris", "ellipsoid_pos_label"],
280
281
  )
281
282
 
282
- temp_xds["SUB_OBSERVER_POSITION"].attrs.update(
283
+ temp_xds["SUB_OBSERVER_DIRECTION"].attrs.update(
283
284
  {
284
285
  "type": "location",
285
286
  "ellipsoid": "NA",
@@ -287,10 +288,10 @@ def extract_ephemeris_info(
287
288
  "coordinate_system": "planetodetic",
288
289
  "units": [
289
290
  cast_to_str(
290
- ephemris_column_description[key_lon]["keywords"][unit_keyword]
291
+ ephemeris_column_description[key_lon]["keywords"][unit_keyword]
291
292
  ),
292
293
  cast_to_str(
293
- ephemris_column_description[key_lat]["keywords"][unit_keyword]
294
+ ephemeris_column_description[key_lat]["keywords"][unit_keyword]
294
295
  ),
295
296
  "m",
296
297
  ],
@@ -306,7 +307,7 @@ def extract_ephemeris_info(
306
307
  ephemeris_xds["r"].data,
307
308
  )
308
309
  ),
309
- dims=["time_ephemeris_axis", "ellipsoid_pos_label"],
310
+ dims=["time_ephemeris", "ellipsoid_pos_label"],
310
311
  )
311
312
  temp_xds["SUB_SOLAR_POSITION"].attrs.update(
312
313
  {
@@ -316,22 +317,22 @@ def extract_ephemeris_info(
316
317
  "coordinate_system": "planetodetic",
317
318
  "units": [
318
319
  cast_to_str(
319
- ephemris_column_description["SI_lon"]["keywords"][unit_keyword]
320
+ ephemeris_column_description["SI_lon"]["keywords"][unit_keyword]
320
321
  ),
321
322
  cast_to_str(
322
- ephemris_column_description["SI_lat"]["keywords"][unit_keyword]
323
+ ephemeris_column_description["SI_lat"]["keywords"][unit_keyword]
323
324
  ),
324
325
  cast_to_str(
325
- ephemris_column_description["r"]["keywords"][unit_keyword]
326
+ ephemeris_column_description["r"]["keywords"][unit_keyword]
326
327
  ),
327
328
  ],
328
329
  }
329
330
  )
330
331
 
331
- # We are using the "time_ephemeris_axis" 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.
332
+ # 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.
332
333
  coords = {
333
334
  "ellipsoid_pos_label": ["lon", "lat", "dist"],
334
- "time_ephemeris_axis": ephemeris_xds["time"].data,
335
+ "time_ephemeris": ephemeris_xds["time"].data,
335
336
  "sky_pos_label": ["ra", "dec", "dist"],
336
337
  }
337
338
  temp_xds = temp_xds.assign_coords(coords)
@@ -341,21 +342,21 @@ def extract_ephemeris_info(
341
342
  "scale": "UTC",
342
343
  "format": "UNIX",
343
344
  }
344
- temp_xds["time_ephemeris_axis"].attrs.update(time_coord_attrs)
345
+ temp_xds["time_ephemeris"].attrs.update(time_coord_attrs)
345
346
 
346
347
  # Convert to si units and interpolate if ephemeris_interpolate=True:
347
348
  temp_xds = convert_to_si_units(temp_xds)
348
349
  temp_xds = interpolate_to_time(
349
- temp_xds, interp_time, "field_and_source_xds", time_name="time_ephemeris_axis"
350
+ temp_xds, interp_time, "field_and_source_xds", time_name="time_ephemeris"
350
351
  )
351
352
 
352
- # If we interpolate rename the time_ephemeris_axis axis to time.
353
+ # If we interpolate rename the time_ephemeris axis to time.
353
354
  if interp_time is not None:
354
- time_coord = {"time": ("time_ephemeris_axis", interp_time.data)}
355
+ time_coord = {"time": ("time_ephemeris", interp_time.data)}
355
356
  temp_xds = temp_xds.assign_coords(time_coord)
356
357
  temp_xds.coords["time"].attrs.update(time_coord_attrs)
357
- temp_xds = temp_xds.swap_dims({"time_ephemeris_axis": "time"}).drop_vars(
358
- "time_ephemeris_axis"
358
+ temp_xds = temp_xds.swap_dims({"time_ephemeris": "time"}).drop_vars(
359
+ "time_ephemeris"
359
360
  )
360
361
 
361
362
  xds = xr.merge([xds, temp_xds])