xradio 0.0.55__py3-none-any.whl → 0.0.58__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 (64) hide show
  1. xradio/__init__.py +2 -2
  2. xradio/_utils/_casacore/casacore_from_casatools.py +1001 -0
  3. xradio/_utils/_casacore/tables.py +6 -1
  4. xradio/_utils/coord_math.py +22 -23
  5. xradio/_utils/dict_helpers.py +76 -11
  6. xradio/_utils/schema.py +5 -2
  7. xradio/_utils/zarr/common.py +1 -73
  8. xradio/image/_util/_casacore/common.py +11 -3
  9. xradio/image/_util/_casacore/xds_from_casacore.py +59 -35
  10. xradio/image/_util/_casacore/xds_to_casacore.py +47 -16
  11. xradio/image/_util/_fits/xds_from_fits.py +172 -77
  12. xradio/image/_util/casacore.py +9 -4
  13. xradio/image/_util/common.py +4 -4
  14. xradio/image/_util/image_factory.py +8 -8
  15. xradio/image/image.py +45 -5
  16. xradio/measurement_set/__init__.py +19 -9
  17. xradio/measurement_set/_utils/__init__.py +1 -3
  18. xradio/measurement_set/_utils/_msv2/__init__.py +0 -0
  19. xradio/measurement_set/_utils/_msv2/_tables/read.py +35 -90
  20. xradio/measurement_set/_utils/_msv2/_tables/read_main_table.py +6 -686
  21. xradio/measurement_set/_utils/_msv2/_tables/table_query.py +13 -3
  22. xradio/measurement_set/_utils/_msv2/conversion.py +129 -145
  23. xradio/measurement_set/_utils/_msv2/create_antenna_xds.py +9 -16
  24. xradio/measurement_set/_utils/_msv2/create_field_and_source_xds.py +125 -221
  25. xradio/measurement_set/_utils/_msv2/msv2_to_msv4_meta.py +1 -2
  26. xradio/measurement_set/_utils/_msv2/msv4_info_dicts.py +13 -8
  27. xradio/measurement_set/_utils/_msv2/msv4_sub_xdss.py +27 -72
  28. xradio/measurement_set/_utils/_msv2/partition_queries.py +5 -262
  29. xradio/measurement_set/_utils/_msv2/subtables.py +0 -107
  30. xradio/measurement_set/_utils/_utils/interpolate.py +60 -0
  31. xradio/measurement_set/_utils/_zarr/encoding.py +2 -7
  32. xradio/measurement_set/convert_msv2_to_processing_set.py +0 -2
  33. xradio/measurement_set/load_processing_set.py +2 -2
  34. xradio/measurement_set/measurement_set_xdt.py +14 -14
  35. xradio/measurement_set/open_processing_set.py +1 -3
  36. xradio/measurement_set/processing_set_xdt.py +41 -835
  37. xradio/measurement_set/schema.py +96 -123
  38. xradio/schema/check.py +91 -97
  39. xradio/schema/dataclass.py +159 -22
  40. xradio/schema/export.py +99 -0
  41. xradio/schema/metamodel.py +51 -16
  42. xradio/schema/typing.py +5 -5
  43. {xradio-0.0.55.dist-info → xradio-0.0.58.dist-info}/METADATA +43 -11
  44. xradio-0.0.58.dist-info/RECORD +65 -0
  45. {xradio-0.0.55.dist-info → xradio-0.0.58.dist-info}/WHEEL +1 -1
  46. xradio/image/_util/fits.py +0 -13
  47. xradio/measurement_set/_utils/_msv2/_tables/load.py +0 -63
  48. xradio/measurement_set/_utils/_msv2/_tables/load_main_table.py +0 -487
  49. xradio/measurement_set/_utils/_msv2/_tables/read_subtables.py +0 -395
  50. xradio/measurement_set/_utils/_msv2/_tables/write.py +0 -320
  51. xradio/measurement_set/_utils/_msv2/_tables/write_exp_api.py +0 -385
  52. xradio/measurement_set/_utils/_msv2/chunks.py +0 -115
  53. xradio/measurement_set/_utils/_msv2/descr.py +0 -165
  54. xradio/measurement_set/_utils/_msv2/msv2_msv3.py +0 -7
  55. xradio/measurement_set/_utils/_msv2/partitions.py +0 -392
  56. xradio/measurement_set/_utils/_utils/cds.py +0 -40
  57. xradio/measurement_set/_utils/_utils/xds_helper.py +0 -404
  58. xradio/measurement_set/_utils/_zarr/read.py +0 -263
  59. xradio/measurement_set/_utils/_zarr/write.py +0 -329
  60. xradio/measurement_set/_utils/msv2.py +0 -106
  61. xradio/measurement_set/_utils/zarr.py +0 -133
  62. xradio-0.0.55.dist-info/RECORD +0 -77
  63. {xradio-0.0.55.dist-info → xradio-0.0.58.dist-info}/licenses/LICENSE.txt +0 -0
  64. {xradio-0.0.55.dist-info → xradio-0.0.58.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
- observer_position = [
218
- ephemeris_meta["GeoLong"],
219
- ephemeris_meta["GeoLat"],
220
- ephemeris_meta["GeoDist"],
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=["ellipsoid_pos_label"]
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": ["deg", "deg", "m"],
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
- ) # I think the units are ['deg','deg','m'] and 'WGS84'.
250
+ )
236
251
 
237
- # Add (optional) data: SOURCE_LOCATION (POSITION / sky_pos_label)
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", "sky_pos_label"],
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
- cast_to_str(ephemeris_column_description["RA"]["keywords"][unit_keyword]),
251
- cast_to_str(ephemeris_column_description["DEC"]["keywords"][unit_keyword]),
252
- cast_to_str(ephemeris_column_description["Rho"]["keywords"][unit_keyword]),
253
- ]
254
- temp_xds["SOURCE_LOCATION"].attrs.update(
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
- "type": "quantity",
286
- "units": [
287
- cast_to_str(
288
- ephemeris_column_description[generic_var_name]["keywords"][
289
- unit_keyword
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", "ellipsoid_pos_label"],
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
- cast_to_str(
324
- ephemeris_column_description[key_lon]["keywords"][unit_keyword]
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["SUB_SOLAR_POSITION"] = xr.DataArray(
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", "ellipsoid_pos_label"],
357
+ dims=["time_ephemeris", "ellipsoid_dir_label"],
344
358
  )
345
- temp_xds["SUB_SOLAR_POSITION"].attrs.update(
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
- cast_to_str(
353
- ephemeris_column_description["SI_lon"]["keywords"][unit_keyword]
354
- ),
355
- cast_to_str(
356
- ephemeris_column_description["SI_lat"]["keywords"][unit_keyword]
357
- ),
358
- cast_to_str(
359
- ephemeris_column_description["r"]["keywords"][unit_keyword]
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
- "ellipsoid_pos_label": ["lon", "lat", "dist"],
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
- source_location_interp = temp_xds["SOURCE_LOCATION"]
404
+ source_direction_interp = temp_xds["SOURCE_DIRECTION"]
405
+ source_distance_interp = temp_xds["SOURCE_DISTANCE"]
406
+
383
407
  else:
384
- source_location_interp = interpolate_to_time(
385
- temp_xds["SOURCE_LOCATION"],
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 SOURCE_LOCATION 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_LOCATION.
394
- # We also need to add a distance dimension to the FIELD_PHASE_CENTER or FIELD_REFERENCE_CENTER to match the SOURCE_LOCATION.
395
- # FIELD_PHASE_CENTER is used for interferometer data and FIELD_REFERENCE_CENTER is used for single dish data.
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
- center_dv = "FIELD_REFERENCE_CENTER"
427
+ center_dir_dv = "FIELD_REFERENCE_CENTER_DIRECTION"
428
+ center_dis_dv = "FIELD_REFERENCE_CENTER_DISTANCE"
398
429
  else:
399
- center_dv = "FIELD_PHASE_CENTER"
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
- source_location_interp
407
- field_phase_center = wrap_to_pi(
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
- field_phase_center = np.column_stack(
412
- (field_phase_center, np.zeros(xds[center_dv].values.shape[0]))
442
+ xds[center_dir_dv] = xr.DataArray(
443
+ field_phase_center_direction,
444
+ dims=["time", "sky_dir_label"],
413
445
  )
414
446
 
415
- field_phase_center[:, -1] = (
416
- field_phase_center[:, -1] + source_location_interp[:, -1].values
447
+ xds[center_dis_dv] = xr.DataArray(
448
+ source_distance_interp.values,
449
+ dims=["time", "sky_dis_label"],
417
450
  )
418
451
 
419
- xds[center_dv] = xr.DataArray(
420
- field_phase_center,
421
- dims=["time", "sky_pos_label"],
422
- )
423
-
424
- # if "time" in xds[center_dv].coords:
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
- # )
452
+ xds[center_dir_dv].attrs.update(xds["SOURCE_DIRECTION"].attrs)
453
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
 
@@ -611,7 +611,7 @@ def extract_source_info(
611
611
 
612
612
  if all(source_id == -1):
613
613
  logger.warning(
614
- f"Source_id is -1. No source information will be included in the field_and_source_xds."
614
+ "Source_id is -1. No source information will be included in the field_and_source_xds."
615
615
  )
616
616
  xds = xds.assign_coords(
617
617
  {"source_name": ("field_name", unknown)}
@@ -655,7 +655,7 @@ def extract_source_info(
655
655
  # ), "Can only process source table with a single time entry for a source_id and spectral_window_id."
656
656
  if len(source_xds.TIME) > len(unique_source_id):
657
657
  logger.warning(
658
- f"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."
658
+ "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
659
  )
660
660
  source_xds = source_xds.drop_duplicates("SOURCE_ID", keep="first")
661
661
 
@@ -689,9 +689,6 @@ def extract_source_info(
689
689
  # If ephemeris data is present we ignore the SOURCE_DIRECTION in the source table.
690
690
  if not is_ephemeris:
691
691
  direction_msv2_col = "DIRECTION"
692
- msv4_measure = column_description_casacore_to_msv4_measure(
693
- source_column_description[direction_msv2_col]
694
- )
695
692
 
696
693
  msv2_direction_dims = source_xds[direction_msv2_col].dims
697
694
  if (
@@ -709,7 +706,7 @@ def extract_source_info(
709
706
  location_msv4_measure = column_description_casacore_to_msv4_measure(
710
707
  source_column_description[direction_msv2_col]
711
708
  )
712
- xds["SOURCE_LOCATION"] = xr.DataArray(
709
+ xds["SOURCE_DIRECTION"] = xr.DataArray(
713
710
  direction_var.data, dims=direction_dims, attrs=location_msv4_measure
714
711
  )
715
712
 
@@ -739,14 +736,15 @@ def extract_source_info(
739
736
 
740
737
  # Need to add doppler info if present. Add check.
741
738
  try:
742
- doppler_xds = load_generic_table(
739
+ load_generic_table(
743
740
  path,
744
741
  "DOPPLER",
745
742
  )
746
- assert (
747
- False
748
- ), "Doppler table present. Please open an issue on https://github.com/casangi/xradio/issues so that we can add support for this."
749
- except:
743
+ logger.warning(
744
+ "Doppler table present. Please open an issue on "
745
+ "https://github.com/casangi/xradio/issues so that we can add support for this."
746
+ )
747
+ except ValueError:
750
748
  pass
751
749
 
752
750
  xds = xds.assign_coords(coords)
@@ -756,50 +754,6 @@ def extract_source_info(
756
754
  return xds, np.sum(num_lines[unique_source_ids_indices])
757
755
 
758
756
 
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
757
  def extract_field_info_and_check_ephemeris(
804
758
  field_and_source_xds: xr.Dataset,
805
759
  in_file: str,
@@ -892,14 +846,17 @@ def extract_field_info_and_check_ephemeris(
892
846
  if is_single_dish:
893
847
  to_new_data_variables = {
894
848
  "REFERENCE_DIR": [
895
- "FIELD_REFERENCE_CENTER",
849
+ "FIELD_REFERENCE_CENTER_DIRECTION",
896
850
  ["field_name", "sky_dir_label"],
897
851
  ],
898
852
  "FIELD_ID": ["FIELD_ID", ["field_name"]],
899
853
  }
900
854
  else:
901
855
  to_new_data_variables = {
902
- "PHASE_DIR": ["FIELD_PHASE_CENTER", ["field_name", "sky_dir_label"]],
856
+ "PHASE_DIR": [
857
+ "FIELD_PHASE_CENTER_DIRECTION",
858
+ ["field_name", "sky_dir_label"],
859
+ ],
903
860
  # "DELAY_DIR": ["FIELD_DELAY_CENTER",["field_name", "sky_dir_label"]],
904
861
  # "REFERENCE_DIR": ["FIELD_REFERENCE_CENTER",["field_name", "sky_dir_label"]],
905
862
  }
@@ -937,59 +894,6 @@ def extract_field_info_and_check_ephemeris(
937
894
  # field_id shouldn ot be in final xds, and no longer needed past this point
938
895
  field_and_source_xds = field_and_source_xds.drop_vars("field_id")
939
896
 
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
897
  return (
994
898
  field_and_source_xds,
995
899
  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"] = ["unkown"]
41
+ attrs_metadata["units"] = "unkown"
43
42
 
44
43
  return attrs_metadata
@@ -1,12 +1,16 @@
1
1
  import numpy as np
2
2
  import xarray as xr
3
3
 
4
- from casacore import tables
4
+ try:
5
+ from casacore import tables
6
+ except ImportError:
7
+ import xradio._utils._casacore.casacore_from_casatools as tables
8
+
5
9
  import toolviper.utils.logger as logger
6
10
 
7
11
  from .subtables import subt_rename_ids
8
12
  from ._tables.read import load_generic_table, convert_casacore_time
9
- from xradio._utils.list_and_array import check_if_consistent, unique_1d, to_list
13
+ from xradio._utils.list_and_array import check_if_consistent
10
14
 
11
15
 
12
16
  def create_info_dicts(
@@ -43,12 +47,13 @@ def create_info_dicts(
43
47
  info dicts ready to be used to update the attrs of the MSv4
44
48
  """
45
49
 
46
- if "line_name" in field_and_source_xds.coords:
47
- line_name = to_list(unique_1d(np.ravel(field_and_source_xds.line_name.values)))
48
- else:
49
- line_name = []
50
-
51
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
+
52
57
  # info_dicts["partition_info"] = {
53
58
  # # "spectral_window_id": xds.frequency.attrs["spectral_window_id"],
54
59
  # "spectral_window_name": xds.frequency.attrs["spectral_window_name"],
@@ -121,7 +126,7 @@ def create_observation_info(in_file: str, observation_id: int):
121
126
  exec_block_xds = load_generic_table(in_file, "ASDM_EXECBLOCK")
122
127
  except ValueError as exc:
123
128
  logger.debug(
124
- "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}"
125
130
  )
126
131
  if exec_block_xds:
127
132
  exec_block_info = extract_exec_block_info(exec_block_xds)