xradio 0.0.6__py3-none-any.whl → 0.0.8__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/data/_dropbox.py CHANGED
@@ -8,18 +8,26 @@ from tqdm import tqdm
8
8
  #https://www.dropbox.com/scl/fi/x8tp0wu21gssbd1gxrnmy/Antennae_North.cal.lsrk.vis.zarr.zip?rlkey=l9jdr6tvyq4pe3381gukuly0d&dl=0
9
9
 
10
10
  FILE_ID = {
11
+ 'AA2-Mid-sim_00000.ms':
12
+ {
13
+ 'file':'AA2-Mid-sim_00000.ms.zip',
14
+ 'id':'2buf75ebhurjlfhe123qs',
15
+ 'rlkey':'8wzgiavzxfp4aza4sx84qanid&dl'
16
+ },
17
+
18
+ 'Antennae_M8.img.zarr':
19
+ {
20
+ 'file':'Antennae_M8.img.zarr.zip',
21
+ 'id':'9v0a1rv7nzm3kqte0u7vp',
22
+ 'rlkey':'ws6vd0jbo1dg7jvxsit42q5ba&dl'
23
+ },
24
+
11
25
  'demo_simulated.im':
12
26
  {
13
27
  'file':'demo_simulated.im.zip',
14
28
  'id':'z87gibxshwg9e2h155ukk',
15
29
  'rlkey':'bn7uvs697wtedij63fa2hu7ed&dl'
16
30
  },
17
- 'Antennae_North.cal.lsrk.vis.zarr':
18
- {
19
- 'file':'Antennae_North.cal.lsrk.vis.zarr.zip',
20
- 'id':'x8tp0wu21gssbd1gxrnmy',
21
- 'rlkey':'l9jdr6tvyq4pe3381gukuly0d&dl'
22
- },
23
31
 
24
32
  'Antennae_North.cal.lsrk.ms':
25
33
  {
@@ -27,6 +35,20 @@ FILE_ID = {
27
35
  'id':'olx5qv9avdxxiyjlhlwx2',
28
36
  'rlkey':'trrqy43rfcqj4blf9robz4p47&dl'
29
37
  },
38
+
39
+ 'Antennae_North.cal.lsrk.vis.zarr':
40
+ {
41
+ 'file':'Antennae_North.cal.lsrk.vis.zarr.zip',
42
+ 'id':'9hcunmq3iqtfiww593nrp',
43
+ 'rlkey':'7fingboduee7logszh25n95x5&dl'
44
+ },
45
+
46
+ 'Antennae_North.cal.lsrk.split.ms':
47
+ {
48
+ 'file':'Antennae_North.cal.lsrk.split.ms.zip',
49
+ 'id':'j2e5pd4y7ppvw9efxdfdj',
50
+ 'rlkey':'hlb85n40vtac3k9nna14giwsf&dl'
51
+ },
30
52
  }
31
53
 
32
54
  def download(file, folder='.'):
xradio/image/__init__.py CHANGED
@@ -1,11 +1,11 @@
1
1
  # methods in cngi_io.image.image should be used going forward,
2
2
  # methods in cngi_io.image.cngi_image_io are deprecated
3
3
  from .image import (
4
- load_image_block, make_empty_sky_image, read_image, write_image
4
+ load_image, make_empty_sky_image, read_image, write_image
5
5
  )
6
6
 
7
7
  __all__ = [
8
- 'load_image_block', 'make_empty_sky_image', 'read_image', 'write_image'
8
+ 'load_image', 'make_empty_sky_image', 'read_image', 'write_image'
9
9
  ]
10
10
 
11
11
 
@@ -61,7 +61,7 @@ def __add_dir_lin_attrs(xds, coord_dict, dir_axes):
61
61
 
62
62
 
63
63
  def __add_freq_attrs(xds, coord_dict):
64
- freq_coord = xds['freq']
64
+ freq_coord = xds['frequency']
65
65
  meta = {}
66
66
  for k in coord_dict:
67
67
  if k.startswith('spectral'):
@@ -89,7 +89,7 @@ def __add_freq_attrs(xds, coord_dict):
89
89
  # this is the default frequency information CASA creates
90
90
  meta = __default_freq_info()
91
91
  freq_coord.attrs = copy.deepcopy(meta)
92
- xds['freq'] = freq_coord
92
+ xds['frequency'] = freq_coord
93
93
  return xds
94
94
 
95
95
 
@@ -282,9 +282,9 @@ def __casa_image_to_xds_metadata(img_full_path:str, verbose:bool=False) -> dict:
282
282
  attrs['sphr_dims'] = sphr_dims
283
283
  coords = {}
284
284
  coords['time'] = __get_time_values(coord_dict)
285
- coords['pol'] = __get_pol_values(coord_dict)
286
- coords['freq'] = __get_freq_values(casa_image.coordinates(), shape)
287
- coords['vel'] = (['freq'], __get_velocity_values(coord_dict, coords['freq']))
285
+ coords['polarization'] = __get_pol_values(coord_dict)
286
+ coords['frequency'] = __get_freq_values(casa_image.coordinates(), shape)
287
+ coords['vel'] = (['frequency'], __get_velocity_values(coord_dict, coords['frequency']))
288
288
  if len(sphr_dims) > 0:
289
289
  for k in coord_dict.keys():
290
290
  if k.startswith('direction'):
@@ -446,11 +446,11 @@ def __get_chunk_list(chunks:dict, coords:list, image_shape:Union[list, tuple]) -
446
446
  if i == 0:
447
447
  axis += 1
448
448
  elif c == 'spectral':
449
- if 'freq' in chunks:
450
- ret_list[axis] = chunks['freq']
449
+ if 'frequency' in chunks:
450
+ ret_list[axis] = chunks['frequency']
451
451
  elif c == 'stokes':
452
- if 'pol' in chunks:
453
- ret_list[axis] = chunks['pol']
452
+ if 'polarization' in chunks:
453
+ ret_list[axis] = chunks['polarization']
454
454
  else:
455
455
  raise Exception(f'Unhandled coordinate type {c}')
456
456
  axis += 1
@@ -468,10 +468,10 @@ def __get_dimmap(coords: list, verbose: bool=False) -> dict:
468
468
  if verbose:
469
469
  print(f'dimmap: {dimmap}')
470
470
  # example of dimmap after next statment
471
- # [('l', 0), ('m', 1), ('chan', 2), ('pol', 3)]
471
+ # [('l', 0), ('m', 1), ('chan', 2), ('polarization', 3)]
472
472
  dimmap = [
473
473
  (rr[0].replace(
474
- 'stokes0','pol'
474
+ 'stokes0','polarization'
475
475
  ).replace('spectral0','chan').replace('direction0','l').replace(
476
476
  'direction1','m').replace('linear0', 'u').replace(
477
477
  'linear1', 'v'
@@ -493,7 +493,7 @@ def __get_dimmap(coords: list, verbose: bool=False) -> dict:
493
493
  for rr in dimmap if rr[1] >= 0
494
494
  ]
495
495
  # conversion to dict, example dimmap after this statement
496
- # dimmap: {'l': 0, 'm': 1, 'chan': 2, 'pol': 3}
496
+ # dimmap: {'l': 0, 'm': 1, 'chan': 2, 'polarization': 3}
497
497
  dimmap = dict(
498
498
  [(diraxes[int(rr[0][-1])], rr[1])
499
499
  if rr[0].startswith('linear') or rr[0].startswith('direction')
@@ -552,10 +552,10 @@ def __get_image_dim_order(coords: coordinates.coordinatesystem) -> list:
552
552
  ret.append('l')
553
553
  elif b.startswith('dec') or b.startswith('vv'):
554
554
  ret.append('m')
555
- elif b.startswith('freq'):
556
- ret.append('freq')
555
+ elif b.startswith('frequency'):
556
+ ret.append('frequency')
557
557
  elif b.startswith('stok'):
558
- ret.append('pol')
558
+ ret.append('polarization')
559
559
  else:
560
560
  raise Exception(f'Unhandled axis name {c}')
561
561
  return ret
@@ -617,7 +617,7 @@ def __get_starts_shapes_slices(
617
617
  shapes = []
618
618
  slices = {}
619
619
  for i, dim in enumerate(img_dim_order):
620
- if dim not in ['pol', 'freq', 'l', 'm', 'u', 'v']:
620
+ if dim not in ['polarization', 'frequency', 'l', 'm', 'u', 'v']:
621
621
  raise Exception(f'Unsupported dimension {dim}')
622
622
  if dim in blockdes:
623
623
  extent = blockdes[dim]
@@ -662,7 +662,7 @@ def __get_transpose_list(coords: coordinates.coordinatesystem) -> list:
662
662
  # transpose_list[4] = csys['pixelmap0'][1]
663
663
  not_covered.remove('m')
664
664
  not_covered.remove('v')
665
- elif b.startswith('freq'):
665
+ elif b.startswith('frequency'):
666
666
  # transpose_list[2] = csys['pixelmap1'][0]
667
667
  transpose_list[2] = i
668
668
  not_covered.remove('f')
@@ -767,7 +767,7 @@ def __multibeam_array(
767
767
  del xds.attrs['beam']
768
768
  if as_dask_array:
769
769
  mb = da.array(mb)
770
- xdb = xr.DataArray(mb, dims=['time', 'pol', 'freq', 'beam_param'])
770
+ xdb = xr.DataArray(mb, dims=['time', 'polarization', 'frequency', 'beam_param'])
771
771
  xdb = xdb.rename('beam')
772
772
  xdb = xdb.assign_coords(beam_param=['major', 'minor', 'pa'])
773
773
  xdb.attrs['unit'] = 'rad'
@@ -869,7 +869,7 @@ def __read_image_array(
869
869
  ) -> dask.array:
870
870
  """
871
871
  Read an array of image pixels into a dask array. The returned dask array
872
- will have axes in time, pol, freq, l, m order
872
+ will have axes in time, polarization, frequency, l, m order
873
873
  If specified, it's the caller's responsibility to ensure the specified blc and
874
874
  trc are coincident with chunk corners. If not, there could be performance degradation
875
875
  The blc, trc box is inclusive of blc pixel coordinates and exclusive trc pixel
@@ -887,7 +887,7 @@ def __read_image_array(
887
887
  Freq, Stokes and the desired chunking is 40 pixels in RA, 30
888
888
  pixels in Dec, 20 pixels in Freq, and 2 pixels in Stokes,
889
889
  chunks would be specified as [40, 30, 20, 2].
890
- If dict, supported optional keys are 'l', 'm', 'freq', 'pol',
890
+ If dict, supported optional keys are 'l', 'm', 'frequency', 'polarization',
891
891
  and 'time'. The supported values are positive integers,
892
892
  indicating the length of a chunk on that particular axis. If
893
893
  a key is missing, the associated chunk length along that axis
@@ -904,7 +904,7 @@ def __read_image_array(
904
904
  :type blc: a type that is convertable to a list via list(blc)
905
905
  :param trc: top right corner, given in the axes ordering of the input image.None=>image shape - 1
906
906
  :type trc: a type that is convertable to a list via list(trc)
907
- :return: Dask array in time, pol, freq, l, m order
907
+ :return: Dask array in time, polarization, frequency, l, m order
908
908
  :rtype: dask.array
909
909
 
910
910
  """
@@ -146,7 +146,7 @@ def __compute_spectral_dict(
146
146
  for a CASA image coordinate system
147
147
  """
148
148
  spec = {}
149
- spec_conv = copy.deepcopy(xds.freq.attrs['conversion'])
149
+ spec_conv = copy.deepcopy(xds.frequency.attrs['conversion'])
150
150
  for k in ('direction', 'epoch', 'position'):
151
151
  spec_conv[k]['type'] = k
152
152
  spec_conv['direction']['refer'] = spec_conv['direction']['system']
@@ -160,19 +160,19 @@ def __compute_spectral_dict(
160
160
  spec['conversion'] = spec_conv
161
161
  spec['formatUnit'] = ''
162
162
  spec['name'] = 'Frequency'
163
- spec['nativeType'] = __native_types.index(xds.freq.attrs['native_type'])
164
- spec['restfreq'] = xds.freq.attrs['restfreq']
165
- spec['restfreqs'] = copy.deepcopy(xds.freq.attrs['restfreqs'])
166
- spec['system'] = xds.freq.attrs['system']
167
- spec['unit'] = xds.freq.attrs['unit']
163
+ spec['nativeType'] = __native_types.index(xds.frequency.attrs['native_type'])
164
+ spec['restfreq'] = xds.frequency.attrs['restfreq']
165
+ spec['restfreqs'] = copy.deepcopy(xds.frequency.attrs['restfreqs'])
166
+ spec['system'] = xds.frequency.attrs['system']
167
+ spec['unit'] = xds.frequency.attrs['unit']
168
168
  spec['velType'] = __doppler_types.index(xds.vel.attrs['doppler_type'])
169
169
  spec['velUnit'] = xds.vel.attrs['unit']
170
170
  spec['version'] = 2
171
- spec['waveUnit'] = xds.freq.attrs['wave_unit']
172
- spec_wcs = copy.deepcopy(xds.freq.attrs['wcs'])
171
+ spec['waveUnit'] = xds.frequency.attrs['wave_unit']
172
+ spec_wcs = copy.deepcopy(xds.frequency.attrs['wcs'])
173
173
  spec_wcs['ctype'] = 'FREQ'
174
174
  spec_wcs['pc'] = 1.0
175
- spec_wcs['crpix'] = (spec_wcs['crval'] - xds.freq.values[0])/spec_wcs['cdelt']
175
+ spec_wcs['crpix'] = (spec_wcs['crval'] - xds.frequency.values[0])/spec_wcs['cdelt']
176
176
  spec['wcs'] = spec_wcs
177
177
  return spec
178
178
 
@@ -195,7 +195,7 @@ def __coord_dict_from_xds(xds: xr.Dataset) -> dict:
195
195
  coord['stokes1'] = {
196
196
  'axes': np.array(['Stokes'], dtype='<U16'), 'cdelt': np.array([1.]),
197
197
  'crpix': np.array([0.]), 'crval': np.array([1.]), 'pc': np.array([[1.]]),
198
- 'stokes': np.array(xds.pol.values, dtype='<U16')
198
+ 'stokes': np.array(xds.polarization.values, dtype='<U16')
199
199
  }
200
200
  coord['spectral2'] = __compute_spectral_dict(
201
201
  xds, coord['direction0'], coord['obsdate'], coord['telescopeposition']
@@ -213,7 +213,7 @@ def __coord_dict_from_xds(xds: xr.Dataset) -> dict:
213
213
  # this probbably needs some verification
214
214
  coord['worldreplace0'] = [0.0, 0.0]
215
215
  coord['worldreplace1'] = np.array(coord['stokes1']['crval'])
216
- coord['worldreplace2'] = np.array([xds.freq.attrs['wcs']['crval']])
216
+ coord['worldreplace2'] = np.array([xds.frequency.attrs['wcs']['crval']])
217
217
  return coord
218
218
 
219
219
 
@@ -259,24 +259,24 @@ def __imageinfo_dict_from_xds(xds: xr.Dataset) -> dict:
259
259
  elif 'beam' in xds.data_vars:
260
260
  # multi beam
261
261
  pp = {}
262
- pp['nChannels'] = len(xds.freq)
263
- pp['nStokes'] = len(xds.pol)
262
+ pp['nChannels'] = len(xds.frequency)
263
+ pp['nStokes'] = len(xds.polarization)
264
264
  bu = xds.beam.attrs['unit']
265
265
  chan = 0
266
- pol = 0
266
+ polarization = 0
267
267
  bv = xds.beam.values
268
268
  for i in range(pp['nChannels'] * pp['nStokes']):
269
- bp = bv[0][pol][chan][:]
269
+ bp = bv[0][polarization][chan][:]
270
270
  b = {
271
271
  'major': {'unit': bu, 'value': bp[0]},
272
272
  'minor': {'unit': bu, 'value': bp[1]},
273
273
  'positionangle': {'unit': bu, 'value': bp[2]}
274
274
  }
275
- pp['*' + str(pp['nChannels']*pol + chan)] = b
275
+ pp['*' + str(pp['nChannels']*polarization + chan)] = b
276
276
  chan += 1
277
277
  if chan >= pp['nChannels']:
278
278
  chan = 0
279
- pol += 1
279
+ polarization += 1
280
280
  ii['perplanebeams'] = pp
281
281
  return ii
282
282
 
@@ -346,7 +346,7 @@ def __write_pixels(
346
346
  tb = tables.table(os.sep.join([image_full_path, active_mask]))
347
347
  tb.copy(filename, deep=True, valuecopy=True)
348
348
  tb.close()
349
- arr = xds[v].isel(time=0).transpose(*('freq', 'pol', 'm', 'l'))
349
+ arr = xds[v].isel(time=0).transpose(*('frequency', 'polarization', 'm', 'l'))
350
350
  chunk_bounds = arr.chunks
351
351
  b = [0, 0, 0, 0]
352
352
  loc0, loc1, loc2, loc3 = (0, 0, 0, 0)
@@ -64,7 +64,7 @@ def __add_time_attrs(xds:xr.Dataset, helpers:dict) -> xr.Dataset:
64
64
 
65
65
 
66
66
  def __add_freq_attrs(xds:xr.Dataset, helpers:dict) -> xr.Dataset:
67
- freq_coord = xds.coords['freq']
67
+ freq_coord = xds.coords['frequency']
68
68
  meta = {}
69
69
  if helpers['has_freq']:
70
70
  conv = {}
@@ -97,7 +97,7 @@ def __add_freq_attrs(xds:xr.Dataset, helpers:dict) -> xr.Dataset:
97
97
  # this is the default frequency information CASA creates
98
98
  meta = __default_freq_info()
99
99
  freq_coord.attrs = copy.deepcopy(meta)
100
- xds['freq'] = freq_coord
100
+ xds['frequency'] = freq_coord
101
101
  return xds
102
102
 
103
103
 
@@ -176,7 +176,7 @@ def __fits_header_to_xds_attrs(hdulist:fits.hdu.hdulist.HDUList) -> dict:
176
176
  elif ax_type.startswith('DEC-'):
177
177
  t_axes[1] = i
178
178
  elif ax_type == 'STOKES':
179
- dim_map['pol'] = i - 1
179
+ dim_map['polarization'] = i - 1
180
180
  elif __is_freq_like(ax_type):
181
181
  dim_map['freq'] = i - 1
182
182
  helpers['has_freq'] = True
@@ -378,9 +378,9 @@ def __create_coords(helpers, header):
378
378
  helpers['sphr_dims'] = sphr_dims
379
379
  coords = {}
380
380
  coords['time'] = __get_time_values(helpers)
381
- coords['pol'] = __get_pol_values(helpers)
382
- coords['freq'] = __get_freq_values(helpers)
383
- coords['vel'] = (['freq'], __get_velocity_values(helpers))
381
+ coords['polarization'] = __get_pol_values(helpers)
382
+ coords['frequency'] = __get_freq_values(helpers)
383
+ coords['vel'] = (['frequency'], __get_velocity_values(helpers))
384
384
  if len(sphr_dims) > 0:
385
385
  l_world, m_world = __compute_world_sph_dims(
386
386
  sphr_dims, dir_axes, dim_map, helpers
@@ -439,7 +439,7 @@ def __get_freq_values(helpers:dict) -> list:
439
439
  freq_start_val = crval - cdelt*crpix
440
440
  for i in range(helpers['shape'][freq_idx]):
441
441
  vals.append(freq_start_val + i*cdelt)
442
- helpers['freq'] = vals * u.Unit(cunit)
442
+ helpers['frequency'] = vals * u.Unit(cunit)
443
443
  return vals
444
444
  elif 'VOPT' in ctype:
445
445
  if 'restfreq' in helpers:
@@ -476,10 +476,10 @@ def __get_freq_values(helpers:dict) -> list:
476
476
  def __get_velocity_values(helpers:dict) -> list:
477
477
  if 'vel' in helpers:
478
478
  return helpers['vel'].to(u.m/u.s).value
479
- elif 'freq' in helpers:
479
+ elif 'frequency' in helpers:
480
480
  if helpers['doppler'] == 'Z':
481
481
  # (-1 + f0/f) = v/c
482
- v = (helpers['restfreq']*u.Hz/helpers['freq'].to('Hz').value - 1) * __c
482
+ v = (helpers['restfreq']*u.Hz/helpers['frequency'].to('Hz').value - 1) * __c
483
483
  v = v.to(u.m/u.s)
484
484
  helpers['vel'] = v
485
485
  return v.value
@@ -557,7 +557,7 @@ def __do_multibeam(xds:xr.Dataset, imname:str) -> xr.Dataset:
557
557
  (beam_array[:, :, :, i] * units[i]).to('rad').value
558
558
  )
559
559
  xdb = xr.DataArray(
560
- beam_array, dims=['time', 'pol', 'freq', 'beam_param']
560
+ beam_array, dims=['time', 'polarization', 'frequency', 'beam_param']
561
561
  )
562
562
  xdb = xdb.rename('beam')
563
563
  xdb = xdb.assign_coords(beam_param=['major', 'minor', 'pa'])
@@ -694,11 +694,11 @@ def __get_chunk_list(chunks:dict, helpers:dict) -> tuple:
694
694
  if 'm' in chunks:
695
695
  ret_list[axis] = chunks['m']
696
696
  elif c.startswith('FREQ') or c.startswith('VOPT') or c.startswith('VRAD'):
697
- if 'freq' in chunks:
698
- ret_list[axis] = chunks['freq']
697
+ if 'frequency' in chunks:
698
+ ret_list[axis] = chunks['frequency']
699
699
  elif c.startswith('STOKES'):
700
- if 'pol' in chunks:
701
- ret_list[axis] = chunks['pol']
700
+ if 'polarization' in chunks:
701
+ ret_list[axis] = chunks['polarization']
702
702
  else:
703
703
  raise RuntimeError(f'Unhandled coordinate type {c}')
704
704
  axis += 1
@@ -723,7 +723,7 @@ def __get_transpose_list(helpers:dict) -> tuple:
723
723
  transpose_list[4] = i
724
724
  not_covered.remove('m')
725
725
  not_covered.remove('v')
726
- elif b.startswith('freq') or b.startswith('vopt') or b.startswith('vrad'):
726
+ elif b.startswith('frequency') or b.startswith('vopt') or b.startswith('vrad'):
727
727
  transpose_list[2] = i
728
728
  not_covered.remove('f')
729
729
  elif b.startswith('stok'):
@@ -0,0 +1,185 @@
1
+ import os
2
+ import numpy as np
3
+ import json
4
+
5
+ from numcodecs.compat import (
6
+ ensure_text,
7
+ ensure_ndarray_like,
8
+ ensure_bytes,
9
+ ensure_contiguous_ndarray_like
10
+ )
11
+
12
+ def pad_array_with_nans(input_array, output_shape):
13
+ """
14
+ Pad an integer array with NaN values to match the specified output shape.
15
+
16
+ Parameters:
17
+ - input_array: The input NumPy array to be padded.
18
+ - output_shape: A tuple specifying the desired output shape (e.g., (rows, columns)).
19
+
20
+ Returns:
21
+ - A NumPy array with NaN padding to match the specified output shape.
22
+ """
23
+ # Get the input shape
24
+ input_shape = input_array.shape
25
+
26
+ # Calculate the padding dimensions
27
+ padding_shape = tuple(max(0, o - i) for i, o in zip(input_shape, output_shape))
28
+
29
+ # Create a new array filled with NaN values
30
+ padded_array = np.empty(output_shape)
31
+ padded_array[:] = np.nan
32
+
33
+ # Copy the input array to the appropriate position within the padded array
34
+ padded_array[:input_shape[0], :input_shape[1]] = input_array
35
+
36
+ return padded_array
37
+
38
+ def write_binary_blob_to_disk(arr, file_path, compressor):
39
+ """
40
+ Compress a NumPy array using Blosc and save it to disk.
41
+
42
+ Parameters:
43
+ - arr: The NumPy array to compress and save.
44
+ - file_path: The path to the output file where the compressed array will be saved.
45
+ - compressor:
46
+
47
+ Returns:
48
+ - None
49
+ """
50
+ # Encode the NumPy array using the codec
51
+ compressed_arr = compressor.encode(arr)
52
+
53
+ # Ensure the directory exists before saving the file
54
+ os.makedirs(os.path.dirname(file_path), exist_ok=True)
55
+
56
+ # Save the compressed array to disk
57
+ with open(file_path, 'wb') as file:
58
+ file.write(compressed_arr)
59
+
60
+ print(f"Compressed array saved to {file_path}")
61
+
62
+ def read_binary_blob_from_disk(file_path, compressor, dtype=np.float64):
63
+ """
64
+ Read a compressed binary blob from disk and decode it using Blosc.
65
+
66
+ Parameters:
67
+ - file_path: The path to the compressed binary blob file.
68
+ - compressor: The Blosc compressor to use (e.g., 'zstd', 'lz4', 'blosclz', etc.).
69
+
70
+ Returns:
71
+ - The decoded NumPy array.
72
+ """
73
+ # Check if the file exists
74
+ if not os.path.exists(file_path):
75
+ print(f"Error: File '{file_path}' not found.")
76
+ return None
77
+
78
+ # Read the compressed binary blob from disk
79
+ with open(file_path, 'rb') as file:
80
+ compressed_arr = file.read()
81
+
82
+ # Decode the compressed data using the Blosc compressor
83
+ decoded_bytes = compressor.decode(compressed_arr)
84
+
85
+ decoded_arr = np.frombuffer(decoded_bytes, dtype) # Adjust dtype as needed
86
+
87
+ return decoded_arr
88
+
89
+
90
+
91
+ def read_json_file(file_path):
92
+ """
93
+ Read a JSON file and return its contents as a Python dictionary.
94
+
95
+ Parameters:
96
+ - file_path: The path to the JSON file to be read.
97
+
98
+ Returns:
99
+ - A Python dictionary containing the JSON data.
100
+ """
101
+ try:
102
+ with open(file_path, 'r') as file:
103
+ data = json.load(file)
104
+ return data
105
+ except FileNotFoundError:
106
+ print(f"Error: File '{file_path}' not found.")
107
+ return None
108
+ except json.JSONDecodeError as e:
109
+ print(f"Error decoding JSON from '{file_path}': {e}")
110
+ return None
111
+
112
+ class NumberEncoder(json.JSONEncoder):
113
+ def default(self, o):
114
+ # See json.JSONEncoder.default docstring for explanation
115
+ # This is necessary to encode numpy dtype
116
+ if isinstance(o, numbers.Integral):
117
+ return int(o)
118
+ if isinstance(o, numbers.Real):
119
+ return float(o)
120
+ return json.JSONEncoder.default(self, o)
121
+
122
+
123
+ def write_json_file(data, file_path):
124
+ """
125
+ Write a Python dictionary to a JSON file.
126
+
127
+ Parameters:
128
+ - data: The Python dictionary to be written to the JSON file.
129
+ - file_path: The path to the JSON file to be created or overwritten.
130
+
131
+ Returns:
132
+ - None
133
+ """
134
+ with open(file_path, 'w') as file:
135
+ json.dump(data, file, indent=4,sort_keys=True, ensure_ascii=True, separators=(",", ": "), cls=NumberEncoder)
136
+
137
+
138
+ def create_data_variable_meta_data_on_disk(zarr_group_name,data_varaibles_and_dims,compressor):
139
+
140
+ for data_varaible, dims in data_varaibles_and_dims.items():
141
+ print(data_varaible,dims)
142
+ data_variable_path = os.path.join(zarr_group_name,data_varaible)
143
+ os.system('mkdir ' + data_variable_path)
144
+ #Create .zattrs
145
+ zattrs = {
146
+ "_ARRAY_DIMENSIONS": dims,
147
+ #"coordinates": "time declination right_ascension"
148
+ }
149
+
150
+ write_json_file(zattrs,os.path.join(data_variable_path,'.zattrs'))
151
+
152
+ #Create .zarray
153
+ from zarr import n5
154
+ compressor_config = n5.compressor_config_to_zarr(n5.compressor_config_to_n5(compressor.get_config()))
155
+ zarray = {
156
+ "chunks": [
157
+ 1,
158
+ 1,
159
+ 2,
160
+ 500,
161
+ 500
162
+ ],
163
+ "compressor":compressor_config,
164
+ "dtype": "<f8",
165
+ "fill_value": "NaN",
166
+ "filters": None,
167
+ "order": "C",
168
+ "shape": [
169
+ 1,
170
+ 1,
171
+ 3,
172
+ 500,
173
+ 500
174
+ ],
175
+ "zarr_format": 2
176
+ }
177
+
178
+ write_json_file(zarray,os.path.join(data_variable_path,'.zarray'))
179
+
180
+
181
+
182
+ ##Image definitions
183
+ # parallel_coords
184
+ # img_xds (get image size and chunk size)
185
+ # SKY, dims, dtype
@@ -72,7 +72,7 @@ def __load_casa_image_block(infile: str, block_des: dict) -> xr.Dataset:
72
72
  mb = __multibeam_array(xds, image_full_path, False)
73
73
  if mb is not None:
74
74
  selectors = {}
75
- for k in ('time', 'pol', 'freq'):
75
+ for k in ('time', 'polarization', 'frequency'):
76
76
  if k in block_des:
77
77
  selectors[k] = block_des[k]
78
78
  xds['beam'] = mb.isel(selectors)
@@ -110,7 +110,7 @@ def __xds_to_casa_image(xds: xr.Dataset, imagename:str) -> None:
110
110
  sky_ap = 'sky' if 'sky' in xds else 'apeature'
111
111
  if xds[sky_ap].shape[0] != 1:
112
112
  raise Exception('XDS can only be converted if it has exactly one time plane')
113
- arr = xds[sky_ap].isel(time=0).transpose(*('freq', 'pol', 'm', 'l'))
113
+ arr = xds[sky_ap].isel(time=0).transpose(*('frequency', 'polarization', 'm', 'l'))
114
114
  image_full_path = os.path.expanduser(imagename)
115
115
  maskname = ''
116
116
  if __active_mask in xds.attrs and xds.attrs[__active_mask]:
@@ -12,7 +12,7 @@ __image_type = 'image_type'
12
12
 
13
13
 
14
14
  def __get_xds_dim_order(has_sph:bool) -> list:
15
- dimorder = ['time', 'pol', 'freq']
15
+ dimorder = ['time', 'polarization', 'frequency']
16
16
  dir_lin = ['l', 'm'] if has_sph else ['u', 'v']
17
17
  dimorder.extend(dir_lin)
18
18
  return dimorder
@@ -46,13 +46,13 @@ def __make_empty_sky_image(
46
46
  time_coords = [ time_coords ]
47
47
  time_coords = np.array(time_coords, dtype=np.float64)
48
48
  coords = {
49
- 'time': time_coords, 'pol': pol_coords, 'freq': chan_coords,
50
- 'vel': (('freq'), vel), 'right_ascension': (('l', 'm'), long),
49
+ 'time': time_coords, 'polarization': pol_coords, 'frequency': chan_coords,
50
+ 'vel': (('frequency'), vel), 'right_ascension': (('l', 'm'), long),
51
51
  'declination': (('l', 'm'), lat)
52
52
  }
53
53
  xds = xds.assign_coords(coords)
54
54
  xds.time.attrs = {'format': 'MJD', 'refer': 'UTC', 'unit': 'd'}
55
- xds.freq.attrs = {
55
+ xds.frequency.attrs = {
56
56
  'conversion': {
57
57
  'direction': {
58
58
  'm0': {'unit': 'rad', 'value': 0.0},
@@ -103,9 +103,11 @@ def __make_empty_sky_image(
103
103
  'conversion_system': direction_reference,
104
104
  'conversion_equinox': 'J2000',
105
105
  'long_pole': 0.0, 'lat_pole': 0.0,
106
- 'pc': np.array([[1.0, 0.0], [0.0, 1.0]]),
106
+ #'pc': np.array([[1.0, 0.0], [0.0, 1.0]]),
107
+ 'pc': [[1.0, 0.0], [0.0, 1.0]],
107
108
  'projection': projection,
108
- 'projection_parameters': np.array([0.0, 0.0]),
109
+ #'projection_parameters': np.array([0.0, 0.0]),
110
+ 'projection_parameters': [0.0, 0.0],
109
111
  'system': direction_reference, 'equinox': 'J2000',
110
112
  },
111
113
  'active_mask': '', 'beam': None, 'object_name': '',
@@ -114,8 +116,11 @@ def __make_empty_sky_image(
114
116
  'value': time_coords[0], 'unit': 'd'
115
117
  },
116
118
  'observer': 'Karl Jansky',
119
+ #'pointing_center': {
120
+ # 'value': np.array(phase_center), 'initial': True
121
+ #},
117
122
  'pointing_center': {
118
- 'value': np.array(phase_center), 'initial': True
123
+ 'value': list(phase_center), 'initial': True
119
124
  },
120
125
  'description': '',
121
126
  'telescope': {
xradio/image/image.py CHANGED
@@ -42,7 +42,7 @@ def read_image(infile:str, chunks:dict={}, verbose:bool=False) -> xr.Dataset:
42
42
  :param infile: Path to the input CASA image
43
43
  :type infile: str, required
44
44
  :param chunks: The desired dask chunk size. Only applicable for casacore and fits images.
45
- Supported optional keys are 'l', 'm', 'freq', 'pol',
45
+ Supported optional keys are 'l', 'm', 'frequency', 'polarization',
46
46
  and 'time'. The supported values are positive integers,
47
47
  indicating the length of a chunk on that particular axis. If
48
48
  a key is missing, then the associated chunk length along that axis
@@ -85,12 +85,12 @@ def read_image(infile:str, chunks:dict={}, verbose:bool=False) -> xr.Dataset:
85
85
  raise RuntimeError('\n'.join(emsgs))
86
86
 
87
87
 
88
- def load_image_block(infile:str, block_des:dict={}) -> xr.Dataset:
89
- """Load an image block (subimage) into memory
88
+ def load_image(infile:str, block_des:dict={}) -> xr.Dataset:
89
+ """Load an image or portion of an image (subimage) into memory
90
90
  :param infile: Path to the input image, currently only casacore images are supported
91
91
  :type infile: str, required
92
92
  :param block_des: The description of data to return, supported keys are time,
93
- pol, freq, l (or u if apeture image), m (or v if apeture image) a
93
+ polarization, frequency, l (or u if apeture image), m (or v if apeture image) a
94
94
  missing key indicates to return the entire axis length for that
95
95
  dimension. Values can be non-negative integers or slices. Slicing
96
96
  behaves as numpy slicing does, that is the start pixel is included in
@@ -104,6 +104,8 @@ def load_image_block(infile:str, block_des:dict={}) -> xr.Dataset:
104
104
  """
105
105
  do_casa = True
106
106
  emsgs = []
107
+
108
+ from ._util.casacore import __read_casa_image
107
109
  try:
108
110
  from ._util.casacore import __read_casa_image
109
111
  except Exception as e:
@@ -17,3 +17,6 @@ class _processing_set(dict):
17
17
  summary_data["end_frequency"].append(value["frequency"].values[-1])
18
18
  summary_df = pd.DataFrame(summary_data)
19
19
  return summary_df
20
+
21
+ def get(self,id):
22
+ return self[list(self.keys())[id]]
@@ -633,14 +633,16 @@ def get_unqiue_intents(infile):
633
633
  rename_ids=subt_rename_ids["STATE"],
634
634
  )
635
635
 
636
- obs_mode_dict = {}
637
- for i, obs_mode in enumerate(state_xds.obs_mode.values):
638
- if obs_mode in obs_mode_dict:
639
- obs_mode_dict[obs_mode].append(i)
640
- else:
641
- obs_mode_dict[obs_mode] = [i]
642
-
643
- return list(obs_mode_dict.keys()), obs_mode_dict.values()
636
+ if len(state_xds.data_vars) > 0:
637
+ obs_mode_dict = {}
638
+ for i, obs_mode in enumerate(state_xds.obs_mode.values):
639
+ if obs_mode in obs_mode_dict:
640
+ obs_mode_dict[obs_mode].append(i)
641
+ else:
642
+ obs_mode_dict[obs_mode] = [i]
643
+ return list(obs_mode_dict.keys()), list(obs_mode_dict.values())
644
+ else: # empty state table
645
+ return ["None"], [0]
644
646
 
645
647
 
646
648
  def enumerated_product(*args):
@@ -674,8 +676,13 @@ def convert_msv2_to_processing_set(
674
676
  field_ids = np.arange(read_generic_table(infile, "FIELD").dims["row"])
675
677
  elif partition_scheme == "ddi_state":
676
678
  state_xds = read_generic_table(infile, "STATE")
677
- state_ids = np.arange(state_xds.dims["row"])
678
- intents = state_xds.obs_mode.values
679
+
680
+ if len(state_xds.data_vars) > 0:
681
+ state_ids = [np.arange(state_xds.dims["row"])]
682
+ intents = state_xds.obs_mode.values
683
+ else: # empty state table
684
+ state_ids = [0]
685
+ intents = ["None"]
679
686
  # print(state_xds, intents)
680
687
  # field_ids = [None]
681
688
  field_ids = np.arange(read_generic_table(infile, "FIELD").dims["row"])
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: xradio
3
- Version: 0.0.6
3
+ Version: 0.0.8
4
4
  Summary: Xarray Radio Astronomy Data IO
5
5
  Author-email: Jan-Willem Steeb <jsteeb@nrao.edu>
6
6
  License: BSD 3-Clause License
@@ -1,27 +1,28 @@
1
1
  xradio/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  xradio/_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  xradio/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- xradio/data/_dropbox.py,sha256=C749TtLFuqEExph4H8HhNYdPSzWzIpBrnUB7tLkZQ5o,1803
4
+ xradio/data/_dropbox.py,sha256=PUz25GUfgjOzzV0-Aim1lF7LSwT3TocPdy2XHlrk7Jo,2288
5
5
  xradio/data/_google_drive.py,sha256=GA3XabwzvA9lBGcHteHYQJhW8pbAXGhMCQBiNeWPphY,4340
6
6
  xradio/data/datasets.py,sha256=rBsum83Qe9v_SIRsD0Ym9roz0dyVKKZrysRXezwkDho,457
7
- xradio/image/__init__.py,sha256=ZhTma3aF9LgC6bEc2Y36QmH7AhfjAAQyVrEfA6JAxsg,303
8
- xradio/image/image.py,sha256=o4T7aAPZc-P0gNKSUeH8Pluke09_ahYuaDHLnQKvuXA,8096
9
- xradio/image/_util/casacore.py,sha256=5d6HwEFTObUa8DchRON03hcz8hoo5g8h7FXAjmITUks,5777
10
- xradio/image/_util/common.py,sha256=QA0NiZWok642pL0mNZ2gSzC79j8nUPEbSV42Oa8fVM0,3947
7
+ xradio/image/__init__.py,sha256=OXBgZQK9f_EgSwW2Uz18GOwsc_OeU1XCHw9IWOybsZk,291
8
+ xradio/image/image.py,sha256=uMA3oEJszImgwThGWJrfBWon6h7n-PoOrMkmGlZPJR8,8190
9
+ xradio/image/_util/casacore.py,sha256=cgb7DVm4HciMQsry0r-gh_peajYUT9V_6GxARgN0Rak,5805
10
+ xradio/image/_util/common.py,sha256=CjCvsxp2NT1rxYs-XeMSAfbGtjL4ZrHdgAR9QIJRZXs,3961
11
11
  xradio/image/_util/fits.py,sha256=NkVxRWH2LPpCHeA0sIqMrJSB8SCiYS9zSNtb0ku0HxM,336
12
- xradio/image/_util/image_factory.py,sha256=0XEgtO8MDCiXhqQvO-WkHExPHNoyQG4uU5JxKpVLqsA,4932
12
+ xradio/image/_util/image_factory.py,sha256=y75Sru2cEXDCA2CnAuDbPIDrxFVjzwZJVjg0--0vrh0,5151
13
13
  xradio/image/_util/zarr.py,sha256=HAmQzvukFGltlMdJhbKRkZhfRYxtX1aPpVKiwQaERtw,454
14
14
  xradio/image/_util/_casacore/__init__.py,sha256=AzU22a8tVAbxO7EAYfE8M3Xn8217YANKiXYtPkewM20,42
15
15
  xradio/image/_util/_casacore/common.py,sha256=FrTjUCdSnDmpfBV6R_gcYo05Uk-Iq36GoLxdmP1tEQg,165
16
- xradio/image/_util/_casacore/xds_from_casacore.py,sha256=HXFpA9UPjBnY-Q60kzfa-Cqtz8oLXmGSkpzHQaoFM8o,38961
17
- xradio/image/_util/_casacore/xds_to_casacore.py,sha256=SFq9n86DUSnyA4yFXjeft1vNJYQX2wWkamzpGC1aj2Q,13795
18
- xradio/image/_util/_fits/xds_from_fits.py,sha256=IOT7tYfYOsnLfsM_IDRJ2YV4UBkRn0-CV_MBMD9OLgM,26537
16
+ xradio/image/_util/_casacore/xds_from_casacore.py,sha256=LzJurgU7X4Eh_fa05Q-LO36mLkh5VcU1ZBPSg2o42Ys,39144
17
+ xradio/image/_util/_casacore/xds_to_casacore.py,sha256=c9RoN_RGVgzxS4ISF13fxOYNr8g6DLxNjh4HZdsI_90,13918
18
+ xradio/image/_util/_fits/xds_from_fits.py,sha256=B1LcJIPEO7IlvXnKpWEHuXlY5O6xgwu5fvPAEd_sq3E,26637
19
19
  xradio/image/_util/_zarr/common.py,sha256=rCntE2QrGMseMJ7DsuWnbNk9kuvCgFFJXMyIzzedo0U,349
20
20
  xradio/image/_util/_zarr/xds_from_zarr.py,sha256=Es97yMB74SY2D_ecY8c_y6M4Vm7eqmvofWWyWe_btUE,1697
21
21
  xradio/image/_util/_zarr/xds_to_zarr.py,sha256=Sh2RbvKHLJx3vOVzDcrurNE215YWbKP1NFGM7zuQFRA,1642
22
+ xradio/image/_util/_zarr/zarr_low_level.py,sha256=KRWx_UO3FwC9CDPTUh7k4ChotVJr6nPIdjkl8raaA9E,5452
22
23
  xradio/vis/__init__.py,sha256=u5CAJpknYDspPF_50istwz70FHSNc3eL8J76ndwgYZo,111
23
- xradio/vis/_processing_set.py,sha256=dpZbhGDvq4EQFBp5-XgUFJ48MYF897_21Xw77UF0SmE,905
24
- xradio/vis/convert_msv2_to_processing_set.py,sha256=liKLEpLTJLuIXCDKrxaokegnIlmUyu8lkBbR4egiMJg,25250
24
+ xradio/vis/_processing_set.py,sha256=vk2mm66bGWxcIoGEk2gYJRPAhYDudB-7tpYmf-2hZ10,979
25
+ xradio/vis/convert_msv2_to_processing_set.py,sha256=9hfm876CPUZRB1OM-dLBUCiNNx1AlBXk4Kk_LR4K-j8,25526
25
26
  xradio/vis/load_processing_set.py,sha256=HXQEjfZThK85sVhwp1JxxUTl1LqedZgAXQFyf9i5Wuw,4505
26
27
  xradio/vis/read_processing_set.py,sha256=E4nIWGz3fDkoOaF1uG09OcmstEN11Do3ekGIHONn2ac,688
27
28
  xradio/vis/vis_io.py,sha256=5b0htEaaAJ1XFJcR2HSNgQmxmmJNW-znrku7-QuPdSo,6022
@@ -49,8 +50,8 @@ xradio/vis/_vis_utils/_utils/stokes_types.py,sha256=rMX7BQFbGFfT6oP54qTit4q16JRA
49
50
  xradio/vis/_vis_utils/_utils/xds_helper.py,sha256=xrS46H7INWTxiuo2zN_a2wOaTr6irbVlkv1efjm7YxY,11853
50
51
  xradio/vis/_vis_utils/_zarr/read.py,sha256=fxznKzP0G8YFjkyMxg04PMI3Mtnu1mMjSnvEhY2arIU,7834
51
52
  xradio/vis/_vis_utils/_zarr/write.py,sha256=fnu9xh_AZ4OfoOGHsMnCpVEZ_2UiZGP7qXhlqZesCCs,9585
52
- xradio-0.0.6.dist-info/LICENSE.txt,sha256=dvACd-5O67yjSZlnEKcWmu3DqwzBtbC922iPv0KOeAw,1516
53
- xradio-0.0.6.dist-info/METADATA,sha256=RmE9rGFyOamgG0DNfZeo2tHyjIR4ufogzwL_8FcjFBQ,4000
54
- xradio-0.0.6.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
55
- xradio-0.0.6.dist-info/top_level.txt,sha256=dQu27fGBZJ2Yk-gW5XeD-dZ76Xa4Xcvk60Vz-dwXp7k,7
56
- xradio-0.0.6.dist-info/RECORD,,
53
+ xradio-0.0.8.dist-info/LICENSE.txt,sha256=dvACd-5O67yjSZlnEKcWmu3DqwzBtbC922iPv0KOeAw,1516
54
+ xradio-0.0.8.dist-info/METADATA,sha256=eqF7XXFxnCMosiqCcXr4rOTl21madMMW19H925MLWKU,4000
55
+ xradio-0.0.8.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
56
+ xradio-0.0.8.dist-info/top_level.txt,sha256=dQu27fGBZJ2Yk-gW5XeD-dZ76Xa4Xcvk60Vz-dwXp7k,7
57
+ xradio-0.0.8.dist-info/RECORD,,
File without changes