Skip to content

Commit 098bd9e

Browse files
authored
Merge pull request #27 from radionets-project/add_times
Change table reading package to casacore, Add times in gridder and uv plotting
2 parents d9773cf + defa799 commit 098bd9e

File tree

4 files changed

+114
-58
lines changed

4 files changed

+114
-58
lines changed

.github/workflows/ci.yml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,6 @@ jobs:
6767
if: matrix.environment-type == 'mamba'
6868
run: micromamba list
6969

70-
- name: Initialize CASAData
71-
run: |
72-
mkdir -p ~/.casa/data/
73-
python -c "import casatools;"
74-
7570
- name: Tests
7671
run: |
7772
pytest -vv --cov --cov-branch --cov-report=xml

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ dependencies = [
4343
"toml",
4444
"torch",
4545
"tqdm",
46-
"casatools",
46+
"python-casacore",
4747
]
4848

4949
[project.optional-dependencies]

pyvisgrid/core/gridder.py

Lines changed: 52 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
import numpy as np
88
from astropy.constants import c
99
from astropy.io import fits
10-
from casatools.table import table
10+
from astropy.time import Time
11+
from casacore.tables import table
1112
from numpy.exceptions import AxisError
1213
from numpy.typing import ArrayLike
1314

@@ -89,6 +90,7 @@ def __init__(
8990
self,
9091
u_meter: np.ndarray,
9192
v_meter: np.ndarray,
93+
times: np.ndarray,
9294
img_size: int,
9395
fov: float,
9496
ref_frequency: float,
@@ -107,6 +109,8 @@ def __init__(
107109
The u coordinates in meter.
108110
v_meter : numpy.ndarray
109111
The v coordinates in meter.
112+
times : numpy.ndarray
113+
The times (in MJD) at which the visibilities were measured.
110114
img_size : int
111115
The size of the image in pixels.
112116
fov : float
@@ -131,6 +135,8 @@ def __init__(
131135
self.u_meter = u_meter
132136
self.v_meter = v_meter
133137

138+
self.times = Time(np.tile(times, reps=self.frequencies.size), format="mjd")
139+
134140
self.img_size = img_size
135141

136142
self.fov = np.deg2rad(fov / 3600) # convert from asec to rad
@@ -281,6 +287,8 @@ def from_pyvisgen(
281287
u_meter = vis_data.u
282288
v_meter = vis_data.v
283289

290+
times = obs.baselines.time / 3600 / 24
291+
284292
vis_data = vis_data.get_values()
285293

286294
if vis_data.ndim != 7:
@@ -295,6 +303,7 @@ def from_pyvisgen(
295303
cls = cls(
296304
u_meter=u_meter.cpu().numpy(),
297305
v_meter=v_meter.cpu().numpy(),
306+
times=times,
298307
img_size=img_size,
299308
fov=fov,
300309
ref_frequency=obs.ref_frequency.cpu().numpy(),
@@ -363,12 +372,6 @@ def from_fits(
363372
uv_colnames = dict(u=None, v=None)
364373

365374
path = Path(path)
366-
367-
if not path.is_file() or path.suffix.lower() != ".fits":
368-
raise FileNotFoundError(
369-
f"The file {path} is not valid! You have to select a valid .fits file!"
370-
)
371-
372375
file = fits.open(path)
373376

374377
data = file[0].data.T
@@ -391,6 +394,8 @@ def from_fits(
391394
u_meter = data[uv_colnames[0]].T * c.value
392395
v_meter = data[uv_colnames[1]].T * c.value
393396

397+
times = Time(data["DATE"], format="jd").mjd
398+
394399
vis = file[0].data["DATA"]
395400
stokes_i = (
396401
(vis[..., 0, 0] + 1j * vis[..., 0, 1])
@@ -400,6 +405,7 @@ def from_fits(
400405
cls = cls(
401406
u_meter=u_meter,
402407
v_meter=v_meter,
408+
times=times,
403409
img_size=img_size,
404410
fov=fov,
405411
ref_frequency=file[0].header["CRVAL4"],
@@ -454,54 +460,52 @@ def from_ms(
454460
f"This measurement set does not exist under the path {path}"
455461
)
456462

457-
tab = table(str(path))
463+
main_tab = table(str(path), ack=False)
464+
spectral_tab = table(str(path / "SPECTRAL_WINDOW"), ack=False)
458465

459466
data_colname = "DATA" if not use_calibrated else "MODEL_DATA"
460467

461468
if desc_id is not None:
462-
mask = tab.getcol("DATA_DESC_ID") == desc_id
469+
mask = main_tab.getcol("DATA_DESC_ID") == desc_id
463470
mask_idx = np.argwhere(mask).ravel()
464471

465-
tab_subset = tab.selectrows(rownrs=mask_idx)
472+
main_tab = main_tab.selectrows(rownrs=mask_idx)
466473

467-
data = tab_subset.getcol(data_colname)
468-
uv = tab_subset.getcol("UVW")[:2]
474+
data = main_tab.getcol(data_colname)
475+
uv = main_tab.getcol("UVW")[:, :2]
476+
times = main_tab.getcol("TIME")
469477

470-
else:
471-
mask = np.ones_like(tab.getcol("DATA_DESC_ID")).astype(bool)
472-
data = tab.getcol(data_colname)
473-
uv = tab.getcol("UVW")[:2]
474-
475-
spectral_tab = table(str(path / "SPECTRAL_WINDOW"))
476-
477-
if desc_id is not None:
478478
ref_frequency = spectral_tab.getcell("REF_FREQUENCY", desc_id)
479-
else:
480-
ref_frequency = spectral_tab.getcell("REF_FREQUENCY", 0)
481-
482-
if desc_id is not None:
483479
frequency_offsets = (
484480
spectral_tab.getcell("CHAN_FREQ", desc_id) - ref_frequency
485481
)
482+
486483
else:
484+
mask = np.ones_like(main_tab.getcol("DATA_DESC_ID")).astype(bool)
485+
data = main_tab.getcol(data_colname)
486+
uv = main_tab.getcol("UVW")[:, :2]
487+
times = main_tab.getcol("TIME")
488+
489+
ref_frequency = spectral_tab.getcell("REF_FREQUENCY", 0)
487490
frequency_offsets = spectral_tab.getcell("CHAN_FREQ", 0) - ref_frequency
488491

489492
if filter_flagged:
490-
flag_mask = tab.getcol("FLAG")[..., mask]
491-
flag_mask = flag_mask.reshape((-1, flag_mask.shape[-1])).astype(np.uint8)
493+
flag_mask = main_tab.getcol("FLAG")
494+
flag_mask = flag_mask.reshape((-1, flag_mask.shape[0])).astype(np.uint8)
492495
flag_mask = np.prod(flag_mask, axis=0)
493496

494497
flag_mask = np.logical_not(flag_mask.astype(bool))
498+
495499
else:
496500
flag_mask = np.ones(uv.shape[-1]).astype(bool)
497501

498-
uv = uv[..., flag_mask]
499-
data = data[..., flag_mask]
502+
uv = uv[flag_mask]
503+
data = data[flag_mask]
500504

501-
u_meter = uv[0]
502-
v_meter = uv[1]
505+
u_meter = uv[:, 0]
506+
v_meter = uv[:, 1]
503507

504-
stokes_i = data[0] + data[1]
508+
stokes_i = data[..., 0] + data[..., 1]
505509

506510
# FIXME: probably some kind of difference in normalization.
507511
# Factor 0.5 fixes this for now. Has to be investigated.
@@ -510,6 +514,7 @@ def from_ms(
510514
cls = cls(
511515
u_meter=u_meter,
512516
v_meter=v_meter,
517+
times=Time(times[flag_mask] / 3600 / 24, format="mjd").mjd,
513518
img_size=img_size,
514519
fov=fov,
515520
ref_frequency=ref_frequency,
@@ -525,12 +530,28 @@ def plot_ungridded_uv(self, **kwargs):
525530
526531
Parameters
527532
----------
533+
gridder : pyvisgrid.Gridder
534+
The gridder from which to take the (u,v) coordinates.
528535
mode : str, optional
529536
The mode specifying the scale of the (u,v) coordinates.
530537
This can be either ``wave``, meaning the coordinates are
531538
plotted in units of the reference wavelength, or ``meter``,
532539
meaning the (u,v) coordinates will be plotted in meter.
533540
Default is ``wave``.
541+
show_times : bool, optional
542+
Whether to show the timestamps of the measured visibilities
543+
as a colormap. Default is ``True``.
544+
use_relative_time : bool, optional
545+
Whether to show the times relative to the timestamp of the
546+
first measurement in hours.
547+
Default is ``True``.
548+
times_cmap: str | matplotlib.colors.Colormap, optional
549+
The colormap to be used for the time component of the plot.
550+
Default is ``'inferno'``.
551+
colorbar_shrink: float, optional
552+
The shrink parameter of the colorbar. This can be needed if the plot is
553+
included as a subplot to adjust the size of the colorbar.
554+
Default is ``1``, meaning original scale.
534555
marker_size : float | None, optional
535556
The size of the scatter markers in points**2.
536557
Default is ``None``, meaning the default value supplied by

0 commit comments

Comments
 (0)