Add code to subtract sources

pull/3/merge
Tammo Jan Dijkema 2020-05-26 21:25:07 +02:00
parent a1968962fa
commit 963aa7f071
4 changed files with 243 additions and 106 deletions

File diff suppressed because one or more lines are too long

View File

@ -25,6 +25,10 @@ Per observation, the following attributes are used:
* extent_lonlat Extent of image in longitude and latitude (w.r.t. WGS84 ellipsoid) * extent_lonlat Extent of image in longitude and latitude (w.r.t. WGS84 ellipsoid)
[lon_min, lon_max, lat_min, lat_max] [lon_min, lon_max, lat_min, lat_max]
* height Height (w.r.t. station phase centre) of the image plane in metres * height Height (w.r.t. station phase centre) of the image plane in metres
* subtracted List of sources subtracted from visibilities
For sky images, the following attributes are used:
* subtracted List of sources subtracted from visibilities
""" """
import datetime import datetime
@ -61,7 +65,8 @@ def get_new_obsname(h5file: h5py.File):
def write_hdf5(filename: str, xst_data: np.ndarray, visibilities: np.ndarray, sky_img: np.ndarray, def write_hdf5(filename: str, xst_data: np.ndarray, visibilities: np.ndarray, sky_img: np.ndarray,
ground_img: np.ndarray, station_name: str, subband: int, rcu_mode: int, frequency: float, ground_img: np.ndarray, station_name: str, subband: int, rcu_mode: int, frequency: float,
obstime: datetime.datetime, extent: List[float], extent_lonlat: List[float], obstime: datetime.datetime, extent: List[float], extent_lonlat: List[float],
height: float, bodies_lmn: Dict[str, Tuple[float]], calibration_info: Dict[str, str]): height: float, bodies_lmn: Dict[str, Tuple[float]], calibration_info: Dict[str, str],
subtracted: List[str]):
""" """
Write an HDF5 file with all data Write an HDF5 file with all data
@ -81,6 +86,7 @@ def write_hdf5(filename: str, xst_data: np.ndarray, visibilities: np.ndarray, sk
height (float): Height of ground image (in metres) height (float): Height of ground image (in metres)
bodies_lmn (Dict[str, Tuple[float]]): lmn coordinates of some objects on the sky bodies_lmn (Dict[str, Tuple[float]]): lmn coordinates of some objects on the sky
calibration_info (Dict[str, str]): Calibration metadata calibration_info (Dict[str, str]): Calibration metadata
subtracted (List[str]): List of sources subtracted
Returns: Returns:
None None
@ -91,7 +97,7 @@ def write_hdf5(filename: str, xst_data: np.ndarray, visibilities: np.ndarray, sk
>>> write_hdf5("test/test.h5", xst_data, visibilities, sky_img, ground_img, "DE603", \ >>> write_hdf5("test/test.h5", xst_data, visibilities, sky_img, ground_img, "DE603", \
297, 3, 150e6, datetime.datetime.now(), [-150, 150, -150, 150], \ 297, 3, 150e6, datetime.datetime.now(), [-150, 150, -150, 150], \
[11.709, 11.713, 50.978, 50.981], 1.5, {'Cas A': (0.3, 0.5, 0.2)}, \ [11.709, 11.713, 50.978, 50.981], 1.5, {'Cas A': (0.3, 0.5, 0.2)}, \
{'CalTableHeader.Calibration.Date': '20181214'}) {'CalTableHeader.Calibration.Date': '20181214'}, ["Cas A", "Sun"])
""" """
short_station_name = station_name[:5] short_station_name = station_name[:5]
@ -110,13 +116,15 @@ def write_hdf5(filename: str, xst_data: np.ndarray, visibilities: np.ndarray, sk
obs_group.create_dataset("calibrated_data", data=visibilities, compression="gzip") obs_group.create_dataset("calibrated_data", data=visibilities, compression="gzip")
for key, value in calibration_info.items(): for key, value in calibration_info.items():
obs_group["calibrated_data"].attrs[key] = value obs_group["calibrated_data"].attrs[key] = value
obs_group.create_dataset("sky_img", data=sky_img, compression="gzip") dataset_sky_img = obs_group.create_dataset("sky_img", data=sky_img, compression="gzip")
dataset_sky_img.attrs["subtracted"] = subtracted
ground_img_group = obs_group.create_group("ground_images") ground_img_group = obs_group.create_group("ground_images")
dataset_ground_img = ground_img_group.create_dataset("ground_img000", data=ground_img, compression="gzip") dataset_ground_img = ground_img_group.create_dataset("ground_img000", data=ground_img, compression="gzip")
dataset_ground_img.attrs["extent"] = extent dataset_ground_img.attrs["extent"] = extent
dataset_ground_img.attrs["extent_lonlat"] = extent_lonlat dataset_ground_img.attrs["extent_lonlat"] = extent_lonlat
dataset_ground_img.attrs["height"] = height dataset_ground_img.attrs["height"] = height
dataset_ground_img.attrs["subtracted"] = str(subtracted)
def merge_hdf5(src_filename: str, dest_filename: str, obslist: List[str] = None): def merge_hdf5(src_filename: str, dest_filename: str, obslist: List[str] = None):

View File

@ -1,5 +1,6 @@
"""Functions for working with LOFAR single station data""" """Functions for working with LOFAR single station data"""
from typing import Dict, List
import numpy as np import numpy as np
from numpy.linalg import norm, lstsq from numpy.linalg import norm, lstsq
import numexpr as ne import numexpr as ne
@ -7,7 +8,8 @@ import numba
from astropy.coordinates import SkyCoord, SkyOffsetFrame, CartesianRepresentation from astropy.coordinates import SkyCoord, SkyOffsetFrame, CartesianRepresentation
__all__ = ["nearfield_imager", "sky_imager", "ground_imager", "skycoord_to_lmn", "calibrate", "simulate_sky_source"] __all__ = ["nearfield_imager", "sky_imager", "ground_imager", "skycoord_to_lmn", "calibrate", "simulate_sky_source",
"subtract_sources"]
__version__ = "1.5.0" __version__ = "1.5.0"
SPEED_OF_LIGHT = 299792458.0 SPEED_OF_LIGHT = 299792458.0
@ -180,13 +182,25 @@ def simulate_sky_source(lmn_coord: np.array, baselines: np.array, freq: float):
return np.exp(2j * np.pi * freq * baselines.dot(np.array(lmn_coord)) / SPEED_OF_LIGHT) return np.exp(2j * np.pi * freq * baselines.dot(np.array(lmn_coord)) / SPEED_OF_LIGHT)
def simulate_nearfield_source(pqr_coord: np.array, baselines: np.array, freq: float): def subtract_sources(vis: np.array, baselines: np.array, freq: float, lmn_dict: Dict[str, np.array],
sources=["Cas A", "Cyg A", "Sun"]):
""" """
Simulate visibilities for a nearfield source Subtract sky sources from visibilities
Args: Args:
pqr_coord (np.array): l, m, n coordinate vis (np.array): visibility matrix, shape [n_ant, n_ant]
lmn_dict (Dict[str, np.array]): dictionary with lmn coordinates
baselines (np.array): baseline distances in metres, shape (n_ant, n_ant) baselines (np.array): baseline distances in metres, shape (n_ant, n_ant)
freq (float): Frequency in Hz freq (float): Frequency in Hz
sources (List[str]): list with source names to subtract (should all be in lmn_dict).
Default ["Cas A", "Sun"]
Returns:
vis (np.array): visibility matrix with sources subtracted
""" """
pass modelvis = [simulate_sky_source(lmn_dict[srcname], baselines, freq) for srcname in lmn_dict
if srcname in sources]
residual, _ = calibrate(vis, modelvis)
return residual

View File

@ -28,7 +28,7 @@ from lofarantpos.db import LofarAntennaDatabase
import lofarantpos import lofarantpos
from .maputil import get_map, make_leaflet_map from .maputil import get_map, make_leaflet_map
from .lofarimaging import nearfield_imager, sky_imager, skycoord_to_lmn from .lofarimaging import nearfield_imager, sky_imager, skycoord_to_lmn, subtract_sources
from .hdf5util import write_hdf5 from .hdf5util import write_hdf5
@ -565,7 +565,8 @@ def make_xst_plots(xst_data: np.ndarray,
sky_only: bool = False, sky_only: bool = False,
opacity: float = 0.6, opacity: float = 0.6,
hdf5_filename: str = None, hdf5_filename: str = None,
outputpath: str = "results"): outputpath: str = "results",
subtract: List[str] = None):
""" """
Create sky and ground plots for an XST file Create sky and ground plots for an XST file
@ -584,6 +585,7 @@ def make_xst_plots(xst_data: np.ndarray,
opacity: Opacity for map overlay. Defaults to 0.6. opacity: Opacity for map overlay. Defaults to 0.6.
hdf5_filename: Filename where hdf5 results can be written. Defaults to outputpath + '/results.h5' hdf5_filename: Filename where hdf5 results can be written. Defaults to outputpath + '/results.h5'
outputpath: Directory where results can be saved. Defaults to 'results' outputpath: Directory where results can be saved. Defaults to 'results'
subtract: List of sources to subtract. Defaults to None
Returns: Returns:
@ -594,7 +596,8 @@ def make_xst_plots(xst_data: np.ndarray,
>>> obstime = datetime.datetime(2017, 7, 20, 9, 58, 16) >>> obstime = datetime.datetime(2017, 7, 20, 9, 58, 16)
>>> sky_fig, ground_fig, leafletmap = make_xst_plots(xst_data, "DE603", obstime, 297, \ >>> sky_fig, ground_fig, leafletmap = make_xst_plots(xst_data, "DE603", obstime, 297, \
3, caltable_dir="test/CalTables", \ 3, caltable_dir="test/CalTables", \
hdf5_filename="test/test.h5") hdf5_filename="test/test.h5", \
subtract=["Cas A", "Sun"])
Maximum at -6m east, 70m north of station center (lat/long 50.97998, 11.71118) Maximum at -6m east, 70m north of station center (lat/long 50.97998, 11.71118)
>>> type(leafletmap) >>> type(leafletmap)
@ -650,10 +653,6 @@ def make_xst_plots(xst_data: np.ndarray,
baselines = station_xyz[:, np.newaxis, :] - station_xyz[np.newaxis, :, :] baselines = station_xyz[:, np.newaxis, :] - station_xyz[np.newaxis, :, :]
# Fourier transform
# visibilities = cube_xx[2,:,:]
sky_img = sky_imager(visibilities_stokesI, baselines, freq, npix_l, npix_m)
obstime_astropy = Time(obstime) obstime_astropy = Time(obstime)
# Determine positions of Cas A and Cyg A # Determine positions of Cas A and Cyg A
station_earthlocation = EarthLocation.from_geocentric(*(db.phase_centres[station_name] * u.m)) station_earthlocation = EarthLocation.from_geocentric(*(db.phase_centres[station_name] * u.m))
@ -679,11 +678,20 @@ def make_xst_plots(xst_data: np.ndarray,
if body_coord.transform_to(AltAz(location=station_earthlocation, obstime=obstime_astropy)).alt > 0: if body_coord.transform_to(AltAz(location=station_earthlocation, obstime=obstime_astropy)).alt > 0:
marked_bodies_lmn[body_name] = skycoord_to_lmn(marked_bodies[body_name], zenith) marked_bodies_lmn[body_name] = skycoord_to_lmn(marked_bodies[body_name], zenith)
if subtract is not None:
visibilities_stokesI = subtract_sources(visibilities_stokesI, baselines, freq, marked_bodies_lmn, subtract)
sky_img = sky_imager(visibilities_stokesI, baselines, freq, npix_l, npix_m)
marked_bodies_lmn_only3 = {k: v for (k, v) in marked_bodies_lmn.items() if k in ('Cas A', 'Cyg A', 'Sun')} marked_bodies_lmn_only3 = {k: v for (k, v) in marked_bodies_lmn.items() if k in ('Cas A', 'Cyg A', 'Sun')}
# Plot the resulting sky image # Plot the resulting sky image
sky_fig = plt.figure(figsize=(10, 10)) sky_fig = plt.figure(figsize=(10, 10))
if sky_vmin is None and subtract is not None:
# Tendency to oversubtract, we don't want to see that
sky_vmin = np.quantile(sky_img, 0.05)
make_sky_plot(sky_img, marked_bodies_lmn_only3, title=f"Sky image for {station_name}", make_sky_plot(sky_img, marked_bodies_lmn_only3, title=f"Sky image for {station_name}",
subtitle=f"SB {subband} ({freq / 1e6:.1f} MHz), {str(obstime)[:16]}", fig=sky_fig, subtitle=f"SB {subband} ({freq / 1e6:.1f} MHz), {str(obstime)[:16]}", fig=sky_fig,
vmin=sky_vmin, vmax=sky_vmax) vmin=sky_vmin, vmax=sky_vmax)
@ -731,10 +739,9 @@ def make_xst_plots(xst_data: np.ndarray,
[maxpixel_p, maxpixel_q, _] = pqr_to_xyz.T @ np.array([maxpixel_x, maxpixel_y, height]) [maxpixel_p, maxpixel_q, _] = pqr_to_xyz.T @ np.array([maxpixel_x, maxpixel_y, height])
maxpixel_lon, maxpixel_lat, _ = lofargeotiff.pqr_to_longlatheight([maxpixel_p, maxpixel_q], station_name) maxpixel_lon, maxpixel_lat, _ = lofargeotiff.pqr_to_longlatheight([maxpixel_p, maxpixel_q], station_name)
# Show location of maximum if not at the image border # Show location of maximum
if 2 < maxpixel_xpix < npix_x - 2 and 2 < maxpixel_ypix < npix_y - 2: print(f"Maximum at {maxpixel_x:.0f}m east, {maxpixel_y:.0f}m north of station center " +
print(f"Maximum at {maxpixel_x:.0f}m east, {maxpixel_y:.0f}m north of station center " + f"(lat/long {maxpixel_lat:.5f}, {maxpixel_lon:.5f})")
f"(lat/long {maxpixel_lat:.5f}, {maxpixel_lon:.5f})")
tags = {"generated_with": f"lofarimaging v{__version__}", tags = {"generated_with": f"lofarimaging v{__version__}",
"subband": subband, "subband": subband,
@ -752,7 +759,7 @@ def make_xst_plots(xst_data: np.ndarray,
leaflet_map = make_leaflet_map(folium_overlay, lon_center, lat_center, lon_min, lat_min, lon_max, lat_max) leaflet_map = make_leaflet_map(folium_overlay, lon_center, lat_center, lon_min, lat_min, lon_max, lat_max)
write_hdf5(hdf5_filename, xst_data, visibilities, sky_img, ground_img, station_name, subband, rcu_mode, write_hdf5(hdf5_filename, xst_data, visibilities, sky_img, ground_img, station_name, subband, rcu_mode,
freq, obstime, extent, extent_lonlat, height, marked_bodies_lmn, calibration_info) freq, obstime, extent, extent_lonlat, height, marked_bodies_lmn, calibration_info, subtract)
return sky_fig, ground_fig, leaflet_map return sky_fig, ground_fig, leaflet_map