Merge 3c177be359
into e183746b8f
commit
1313681c22
|
@ -170,8 +170,7 @@
|
||||||
"output_type": "stream",
|
"output_type": "stream",
|
||||||
"text": [
|
"text": [
|
||||||
"Searching for available files in ./test\n",
|
"Searching for available files in ./test\n",
|
||||||
"0: ./test/20200525_084652_mode_5_xst_sb100.dat\n",
|
"0: ./test/20170720_095816_mode_3_xst_sb297.dat\n"
|
||||||
"1: ./test/20170720_095816_mode_3_xst_sb297.dat\n"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -198,7 +197,7 @@
|
||||||
],
|
],
|
||||||
"source": [
|
"source": [
|
||||||
"# Select a file\n",
|
"# Select a file\n",
|
||||||
"xst_filename = files[1]\n",
|
"xst_filename = files[0]\n",
|
||||||
"\n",
|
"\n",
|
||||||
"print(\"File selected:\", xst_filename)"
|
"print(\"File selected:\", xst_filename)"
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,15 +1,18 @@
|
||||||
"""Functions for working with LOFAR single station data"""
|
"""Functions for working with LOFAR single station data"""
|
||||||
|
|
||||||
|
import logging
|
||||||
from typing import Dict, List
|
from typing import Dict, List
|
||||||
import numpy as np
|
|
||||||
from numpy.linalg import norm, lstsq
|
|
||||||
import numexpr as ne
|
|
||||||
import numba
|
|
||||||
from astropy.coordinates import SkyCoord, SkyOffsetFrame, CartesianRepresentation
|
|
||||||
|
|
||||||
|
import numba
|
||||||
|
import numexpr as ne
|
||||||
|
import numpy as np
|
||||||
|
import scipy.optimize
|
||||||
|
from astropy.coordinates import SkyCoord, SkyOffsetFrame, CartesianRepresentation
|
||||||
|
from numpy.linalg import norm, lstsq
|
||||||
|
|
||||||
__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"]
|
"subtract_sources", "compute_calibrated_model", "compute_pointing_matrix", "estimate_model_visibilities",
|
||||||
|
"estimate_sources_flux", "self_cal"]
|
||||||
|
|
||||||
__version__ = "1.5.0"
|
__version__ = "1.5.0"
|
||||||
SPEED_OF_LIGHT = 299792458.0
|
SPEED_OF_LIGHT = 299792458.0
|
||||||
|
@ -170,13 +173,144 @@ def calibrate(vis, modelvis, maxiter=30, amplitudeonly=True):
|
||||||
return residual, gains
|
return residual, gains
|
||||||
|
|
||||||
|
|
||||||
|
def compute_calibrated_model(vis, model_vis, maxiter=30):
|
||||||
|
"""
|
||||||
|
Calibrate the gains phases and apply to the model
|
||||||
|
|
||||||
|
Args:
|
||||||
|
vis: visibility matrix, shape [n_st, n_st]
|
||||||
|
model_vis: model visibility matrix, shape [n_st, n_st]
|
||||||
|
maxiter: max iterations (default 30)
|
||||||
|
Returns:
|
||||||
|
calibrated: model visibilities, shape [n_st, n_st]
|
||||||
|
gains: the antenna gains, shape [n_st]
|
||||||
|
residual: amplitude difference between model and actual visibilities, float
|
||||||
|
"""
|
||||||
|
|
||||||
|
n_ant = vis.shape[0]
|
||||||
|
gain_phase = np.zeros((n_ant), dtype=complex)
|
||||||
|
|
||||||
|
def gains_difference(gain_phase, vis, model_vis):
|
||||||
|
gains = np.exp(1.j * gain_phase)
|
||||||
|
gains_mat = np.diag(gains)
|
||||||
|
gains_mat_star = np.diag(np.conj(gains))
|
||||||
|
predicted = gains_mat_star @ model_vis @ gains_mat
|
||||||
|
residual = np.sum(np.abs(vis - predicted))
|
||||||
|
return residual
|
||||||
|
|
||||||
|
result = scipy.optimize.minimize(gains_difference, gain_phase, args=(vis, model_vis), options={'maxiter': maxiter})
|
||||||
|
gain_phase = result.x
|
||||||
|
gains = np.exp(1.j * gain_phase)
|
||||||
|
gains_mat = np.diag(gains)
|
||||||
|
calibrated = np.conj(gains_mat) @ model_vis @ gains_mat
|
||||||
|
|
||||||
|
return calibrated, gains, gains_difference(gain_phase, vis, model_vis)
|
||||||
|
|
||||||
|
|
||||||
|
def compute_pointing_matrix(sources_positions, baselines, frequency):
|
||||||
|
"""
|
||||||
|
Compute the pointing matrix used to compute the visibilities from
|
||||||
|
the sources position
|
||||||
|
|
||||||
|
Args:
|
||||||
|
sources_positions: matrix of the lmn sources position, shape [n_dir, 3]
|
||||||
|
baselines: baseline matrix, shape [n_st, n_st]
|
||||||
|
frequency: frequency
|
||||||
|
Returns:
|
||||||
|
pointing_matrix: pointing matrix, shape [n_st, n_st, n_dir]
|
||||||
|
"""
|
||||||
|
n_baselines = baselines.shape[0]
|
||||||
|
n_sources = sources_positions.shape[0]
|
||||||
|
|
||||||
|
pointing_matrix = np.zeros(shape=(n_baselines, n_baselines, n_sources), dtype=complex)
|
||||||
|
|
||||||
|
for q in range(n_sources):
|
||||||
|
pointing_matrix[:, :, q] = simulate_sky_source(sources_positions[q, :], baselines, frequency)
|
||||||
|
return pointing_matrix
|
||||||
|
|
||||||
|
|
||||||
|
def estimate_sources_flux(visibilities, pointing_matrix):
|
||||||
|
"""
|
||||||
|
Estimate the flux of the sources given the pointing matrix and the measured visibilities
|
||||||
|
|
||||||
|
Args:
|
||||||
|
visibilities: visibilities, shape [n_st, n_st]
|
||||||
|
pointing_matrix: pointing matrix, shape [n_st, n_st, n_dir]
|
||||||
|
Returns:
|
||||||
|
fluxes: amplitude of the source at the given direction, shape [n_st, n_st, n_dir]
|
||||||
|
"""
|
||||||
|
|
||||||
|
def residual_flux(signal, vis, point_matrix):
|
||||||
|
residual = vis - point_matrix @ signal
|
||||||
|
residual = np.sum(np.abs(residual))
|
||||||
|
return residual
|
||||||
|
|
||||||
|
n_antennas = visibilities.shape[0]
|
||||||
|
n_sources = pointing_matrix.shape[2]
|
||||||
|
lin_visibilities = visibilities.reshape((n_antennas * n_antennas))
|
||||||
|
lin_pointing_matrix = pointing_matrix.reshape((n_antennas * n_antennas, n_sources))
|
||||||
|
fluxes, *_ = np.linalg.lstsq(lin_pointing_matrix, lin_visibilities)
|
||||||
|
|
||||||
|
result = scipy.optimize.minimize(residual_flux, fluxes, args=(visibilities, pointing_matrix))
|
||||||
|
fluxes = result.x
|
||||||
|
return fluxes
|
||||||
|
|
||||||
|
|
||||||
|
def estimate_model_visibilities(sources_positions, visibilities, baselines, frequency):
|
||||||
|
"""
|
||||||
|
Estimate the visibilities of the models given the sources position and the measured visibilities
|
||||||
|
|
||||||
|
Args:
|
||||||
|
sources_positions: lmn coords of the sources, shape [n_dir, 3]
|
||||||
|
visibilities: visibilities, shape [n_st, n_st]
|
||||||
|
baselines: baselines matrix in m, shape [n_st, n_st, 3]
|
||||||
|
frequency: frequency
|
||||||
|
Returns:
|
||||||
|
model: the model visibilities, shape [n_st, n_st]
|
||||||
|
"""
|
||||||
|
pointing_matrix = compute_pointing_matrix(sources_positions, baselines, frequency)
|
||||||
|
fluxes = estimate_sources_flux(visibilities, pointing_matrix)
|
||||||
|
model = pointing_matrix @ fluxes
|
||||||
|
|
||||||
|
return model
|
||||||
|
|
||||||
|
|
||||||
|
def self_cal(visibilities, expected_sources, baselines, frequency, max_iterations=10, tolerance=1.e-4):
|
||||||
|
"""
|
||||||
|
Compute the gain phase comparing the model and the actual visibilities returning
|
||||||
|
the model with the gain phase correction applied.
|
||||||
|
|
||||||
|
|
||||||
|
Args:
|
||||||
|
visibilities: visibilities, shape [n_st, n_st]
|
||||||
|
expected_sources: lmn coords of the sources, shape [n_dir, 3]
|
||||||
|
baselines: baselines matrix in m, shape [n_st, n_st, 3]
|
||||||
|
frequency: frequency
|
||||||
|
max_iterations: maximum number of iterations to perform
|
||||||
|
Returns:
|
||||||
|
model: the model visibilities with the applied gains, shape [n_st, n_st]
|
||||||
|
gains: the antenna gains, shape [n_st]
|
||||||
|
|
||||||
|
"""
|
||||||
|
model = estimate_model_visibilities(expected_sources, visibilities, baselines, frequency)
|
||||||
|
model, gains, residual = compute_calibrated_model(visibilities, model, maxiter=50)
|
||||||
|
for i in range(1, max_iterations):
|
||||||
|
model, gains, next_residual = compute_calibrated_model(visibilities, model, maxiter=50)
|
||||||
|
if next_residual != 0 and abs(1 - (residual / next_residual)) >= tolerance:
|
||||||
|
residual = next_residual
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
return model, gains
|
||||||
|
|
||||||
|
|
||||||
def simulate_sky_source(lmn_coord: np.array, baselines: np.array, freq: float):
|
def simulate_sky_source(lmn_coord: np.array, baselines: np.array, freq: float):
|
||||||
"""
|
"""
|
||||||
Simulate visibilities for a sky source
|
Simulate visibilities for a sky source
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
lmn_coord (np.array): l, m, n coordinate
|
lmn_coord (np.array): l, m, n coordinate
|
||||||
baselines (np.array): baseline distances in metres, shape (n_ant, n_ant)
|
baselines (np.array): baseline distances in metres, shape (n_ant, n_ant, 3)
|
||||||
freq (float): Frequency in Hz
|
freq (float): Frequency in Hz
|
||||||
"""
|
"""
|
||||||
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)
|
||||||
|
|
|
@ -1,36 +1,32 @@
|
||||||
"""Functions for working with LOFAR single station data"""
|
"""Functions for working with LOFAR single station data"""
|
||||||
|
|
||||||
import os
|
|
||||||
import datetime
|
import datetime
|
||||||
|
import os
|
||||||
from typing import List, Dict, Tuple, Union
|
from typing import List, Dict, Tuple, Union
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
from packaging import version
|
|
||||||
import tqdm
|
|
||||||
import h5py
|
|
||||||
|
|
||||||
import matplotlib.pyplot as plt
|
|
||||||
import matplotlib.animation
|
|
||||||
from matplotlib.ticker import FormatStrFormatter
|
|
||||||
from matplotlib import cm
|
|
||||||
from matplotlib.figure import Figure
|
|
||||||
from matplotlib.colors import ListedColormap, Normalize
|
|
||||||
from matplotlib.patches import Circle
|
|
||||||
import matplotlib.axes as maxes
|
|
||||||
from mpl_toolkits.axes_grid1 import make_axes_locatable
|
|
||||||
|
|
||||||
from astropy.coordinates import SkyCoord, GCRS, EarthLocation, AltAz, get_sun, get_moon
|
|
||||||
import astropy.units as u
|
import astropy.units as u
|
||||||
from astropy.time import Time
|
import h5py
|
||||||
|
|
||||||
import lofargeotiff
|
|
||||||
from lofarantpos.db import LofarAntennaDatabase
|
|
||||||
import lofarantpos
|
import lofarantpos
|
||||||
|
import lofargeotiff
|
||||||
|
import matplotlib.animation
|
||||||
|
import matplotlib.axes as maxes
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import numpy as np
|
||||||
|
import tqdm
|
||||||
|
from astropy.coordinates import SkyCoord, GCRS, EarthLocation, AltAz, get_sun, get_moon
|
||||||
|
from astropy.time import Time
|
||||||
|
from lofarantpos.db import LofarAntennaDatabase
|
||||||
|
from matplotlib import cm
|
||||||
|
from matplotlib.colors import ListedColormap, Normalize
|
||||||
|
from matplotlib.figure import Figure
|
||||||
|
from matplotlib.patches import Circle
|
||||||
|
from matplotlib.ticker import FormatStrFormatter
|
||||||
|
from mpl_toolkits.axes_grid1 import make_axes_locatable
|
||||||
|
from packaging import version
|
||||||
|
|
||||||
from .maputil import get_map, make_leaflet_map
|
|
||||||
from .lofarimaging import nearfield_imager, sky_imager, skycoord_to_lmn, subtract_sources
|
|
||||||
from .hdf5util import write_hdf5
|
from .hdf5util import write_hdf5
|
||||||
|
from .lofarimaging import nearfield_imager, sky_imager, skycoord_to_lmn, subtract_sources
|
||||||
|
from .maputil import get_map, make_leaflet_map
|
||||||
|
|
||||||
__all__ = ["sb_from_freq", "freq_from_sb", "find_caltable", "read_caltable",
|
__all__ = ["sb_from_freq", "freq_from_sb", "find_caltable", "read_caltable",
|
||||||
"rcus_in_station", "read_acm_cube", "get_station_pqr", "get_station_type",
|
"rcus_in_station", "read_acm_cube", "get_station_pqr", "get_station_type",
|
||||||
|
@ -331,7 +327,7 @@ def get_station_pqr(station_name: str, rcu_mode: Union[str, int], db):
|
||||||
'intl': GENERIC_INT_201512, 'remote': GENERIC_REMOTE_201512, 'core': GENERIC_CORE_201512
|
'intl': GENERIC_INT_201512, 'remote': GENERIC_REMOTE_201512, 'core': GENERIC_CORE_201512
|
||||||
}
|
}
|
||||||
selected_dipoles = selected_dipole_config[station_type] + \
|
selected_dipoles = selected_dipole_config[station_type] + \
|
||||||
np.arange(len(selected_dipole_config[station_type])) * 16
|
np.arange(len(selected_dipole_config[station_type])) * 16
|
||||||
station_pqr = db.hba_dipole_pqr(full_station_name)[selected_dipoles]
|
station_pqr = db.hba_dipole_pqr(full_station_name)[selected_dipoles]
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("Station name did not contain LBA or HBA, could not load antenna positions")
|
raise RuntimeError("Station name did not contain LBA or HBA, could not load antenna positions")
|
||||||
|
@ -340,7 +336,7 @@ def get_station_pqr(station_name: str, rcu_mode: Union[str, int], db):
|
||||||
|
|
||||||
|
|
||||||
def make_ground_plot(image: np.ndarray, background_map: np.ndarray, extent: List[float], title: str = "Ground plot",
|
def make_ground_plot(image: np.ndarray, background_map: np.ndarray, extent: List[float], title: str = "Ground plot",
|
||||||
subtitle: str = "", opacity: float = 0.6, fig: Figure = None, draw_contours: bool = True, **kwargs) \
|
subtitle: str = "", opacity: float = 0.6, fig: Figure = None, draw_contours: bool = True, **kwargs) \
|
||||||
-> Tuple[Figure, np.ndarray]:
|
-> Tuple[Figure, np.ndarray]:
|
||||||
"""
|
"""
|
||||||
Make a ground plot of an array with data
|
Make a ground plot of an array with data
|
||||||
|
@ -585,7 +581,6 @@ 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:
|
||||||
|
@ -662,14 +657,14 @@ def make_xst_plots(xst_data: np.ndarray,
|
||||||
marked_bodies = {
|
marked_bodies = {
|
||||||
'Cas A': SkyCoord(ra=350.85 * u.deg, dec=58.815 * u.deg),
|
'Cas A': SkyCoord(ra=350.85 * u.deg, dec=58.815 * u.deg),
|
||||||
'Cyg A': SkyCoord(ra=299.86815191 * u.deg, dec=40.73391574 * u.deg),
|
'Cyg A': SkyCoord(ra=299.86815191 * u.deg, dec=40.73391574 * u.deg),
|
||||||
'Per A': SkyCoord(ra=49.95066567*u.deg, dec=41.51169838 * u.deg),
|
'Per A': SkyCoord(ra=49.95066567 * u.deg, dec=41.51169838 * u.deg),
|
||||||
'Her A': SkyCoord(ra=252.78343333*u.deg, dec=4.99303056*u.deg),
|
'Her A': SkyCoord(ra=252.78343333 * u.deg, dec=4.99303056 * u.deg),
|
||||||
'Cen A': SkyCoord(ra=201.36506288*u.deg, dec=-43.01911267*u.deg),
|
'Cen A': SkyCoord(ra=201.36506288 * u.deg, dec=-43.01911267 * u.deg),
|
||||||
'Vir A': SkyCoord(ra=187.70593076*u.deg, dec=12.39112329*u.deg),
|
'Vir A': SkyCoord(ra=187.70593076 * u.deg, dec=12.39112329 * u.deg),
|
||||||
'3C295': SkyCoord(ra=212.83527917*u.deg, dec=52.20264444*u.deg),
|
'3C295': SkyCoord(ra=212.83527917 * u.deg, dec=52.20264444 * u.deg),
|
||||||
'Moon': get_moon(obstime_astropy, location=station_earthlocation).transform_to(GCRS),
|
'Moon': get_moon(obstime_astropy, location=station_earthlocation).transform_to(GCRS),
|
||||||
'Sun': get_sun(obstime_astropy),
|
'Sun': get_sun(obstime_astropy),
|
||||||
'3C196': SkyCoord(ra=123.40023371*u.deg, dec=48.21739888*u.deg)
|
'3C196': SkyCoord(ra=123.40023371 * u.deg, dec=48.21739888 * u.deg)
|
||||||
}
|
}
|
||||||
|
|
||||||
marked_bodies_lmn = {}
|
marked_bodies_lmn = {}
|
||||||
|
@ -752,7 +747,7 @@ def make_xst_plots(xst_data: np.ndarray,
|
||||||
"pixels_per_metre": pixels_per_metre}
|
"pixels_per_metre": pixels_per_metre}
|
||||||
tags.update(calibration_info)
|
tags.update(calibration_info)
|
||||||
lon_min, lon_max, lat_min, lat_max = extent_lonlat
|
lon_min, lon_max, lat_min, lat_max = extent_lonlat
|
||||||
lofargeotiff.write_geotiff(ground_img[::-1,:], os.path.join(outputpath, f"{fname}_nearfield_calibrated.tiff"),
|
lofargeotiff.write_geotiff(ground_img[::-1, :], os.path.join(outputpath, f"{fname}_nearfield_calibrated.tiff"),
|
||||||
(lon_min, lat_max), (lon_max, lat_min), as_pqr=False,
|
(lon_min, lat_max), (lon_max, lat_min), as_pqr=False,
|
||||||
stationname=station_name, obsdate=obstime, tags=tags)
|
stationname=station_name, obsdate=obstime, tags=tags)
|
||||||
|
|
||||||
|
@ -769,7 +764,7 @@ def make_sky_movie(moviefilename: str, h5file: h5py.File, obsnums: List[str], vm
|
||||||
"""
|
"""
|
||||||
Make movie of a list of observations
|
Make movie of a list of observations
|
||||||
"""
|
"""
|
||||||
fig = plt.figure(figsize=(10,10))
|
fig = plt.figure(figsize=(10, 10))
|
||||||
for obsnum in tqdm.tqdm(obsnums):
|
for obsnum in tqdm.tqdm(obsnums):
|
||||||
obs_h5 = h5file[obsnum]
|
obs_h5 = h5file[obsnum]
|
||||||
skydata_h5 = obs_h5["sky_img"]
|
skydata_h5 = obs_h5["sky_img"]
|
||||||
|
@ -787,7 +782,28 @@ def make_sky_movie(moviefilename: str, h5file: h5py.File, obsnums: List[str], vm
|
||||||
|
|
||||||
# Thanks to Maaijke Mevius for making this animation work!
|
# Thanks to Maaijke Mevius for making this animation work!
|
||||||
ims = fig.get_children()[1:]
|
ims = fig.get_children()[1:]
|
||||||
ims = [ims[i:i+2] for i in range(0, len(ims), 2)]
|
ims = [ims[i:i + 2] for i in range(0, len(ims), 2)]
|
||||||
ani = matplotlib.animation.ArtistAnimation(fig, ims, interval=30, blit=False, repeat_delay=1000)
|
ani = matplotlib.animation.ArtistAnimation(fig, ims, interval=30, blit=False, repeat_delay=1000)
|
||||||
writer = matplotlib.animation.writers['ffmpeg'](fps=5, bitrate=800)
|
writer = matplotlib.animation.writers['ffmpeg'](fps=5, bitrate=800)
|
||||||
ani.save(moviefilename, writer=writer, dpi=fig.dpi)
|
ani.save(moviefilename, writer=writer, dpi=fig.dpi)
|
||||||
|
|
||||||
|
|
||||||
|
def compute_baselines(station_name, rcu_mode):
|
||||||
|
# Setup the database
|
||||||
|
db = LofarAntennaDatabase()
|
||||||
|
|
||||||
|
station_pqr = get_station_pqr(station_name, rcu_mode, db)
|
||||||
|
|
||||||
|
station_name = get_full_station_name(station_name, rcu_mode)
|
||||||
|
|
||||||
|
# Rotate station_pqr to a north-oriented xyz frame, where y points North, in a plane through the station.
|
||||||
|
rotation = db.rotation_from_north(station_name)
|
||||||
|
|
||||||
|
pqr_to_xyz = np.array([[np.cos(-rotation), -np.sin(-rotation), 0],
|
||||||
|
[np.sin(-rotation), np.cos(-rotation), 0],
|
||||||
|
[0, 0, 1]])
|
||||||
|
|
||||||
|
station_xyz = (pqr_to_xyz @ station_pqr.T).T
|
||||||
|
|
||||||
|
baselines = station_xyz[:, np.newaxis, :] - station_xyz[np.newaxis, :, :]
|
||||||
|
return baselines
|
||||||
|
|
|
@ -13,3 +13,4 @@ Pillow
|
||||||
opcua
|
opcua
|
||||||
h5py
|
h5py
|
||||||
tqdm
|
tqdm
|
||||||
|
scipy
|
|
@ -0,0 +1,77 @@
|
||||||
|
import numpy
|
||||||
|
from numpy.testing import assert_almost_equal
|
||||||
|
|
||||||
|
from lofarimaging.lofarimaging import compute_calibrated_model, \
|
||||||
|
compute_pointing_matrix, simulate_sky_source, \
|
||||||
|
estimate_sources_flux, \
|
||||||
|
estimate_model_visibilities, \
|
||||||
|
self_cal
|
||||||
|
|
||||||
|
|
||||||
|
def test_compute_calibrated_model():
|
||||||
|
# ----TEST DATA
|
||||||
|
vis = numpy.diag(numpy.ones((10)))
|
||||||
|
model_vis = numpy.diag(numpy.ones(10))
|
||||||
|
# ----TEST
|
||||||
|
calibrated, gains, residual = compute_calibrated_model(vis, model_vis)
|
||||||
|
assert_almost_equal(calibrated, vis)
|
||||||
|
assert residual < 1.e-5
|
||||||
|
|
||||||
|
|
||||||
|
def test_simulate_sky_source():
|
||||||
|
# ----TEST DATA
|
||||||
|
source_position = [0, 0, 0]
|
||||||
|
baselines = numpy.zeros((2, 2, 3))
|
||||||
|
baselines[0, 1, :] = [1, 0, 0]
|
||||||
|
baselines[1, 0, :] = [1, 0, 0]
|
||||||
|
# ----TEST
|
||||||
|
visibilities = simulate_sky_source(source_position, baselines, 1)
|
||||||
|
expected = numpy.ones((2, 2))
|
||||||
|
assert_almost_equal(visibilities, expected)
|
||||||
|
|
||||||
|
|
||||||
|
def test_compute_pointing_matrix():
|
||||||
|
# ----TEST DATA
|
||||||
|
source_position = numpy.zeros((1, 3))
|
||||||
|
baselines = numpy.zeros((2, 2, 3))
|
||||||
|
baselines[0, 1, :] = [1, 0, 0]
|
||||||
|
baselines[1, 0, :] = [1, 0, 0]
|
||||||
|
expected = numpy.ones((2, 2, 1))
|
||||||
|
# ----TEST
|
||||||
|
pointing_matrix = compute_pointing_matrix(source_position, baselines, 1)
|
||||||
|
assert_almost_equal(pointing_matrix, expected)
|
||||||
|
|
||||||
|
|
||||||
|
def test_estimate_sources_flux():
|
||||||
|
# ----TEST DATA
|
||||||
|
source_position = numpy.zeros((1, 3))
|
||||||
|
pointing_matrix = numpy.ones((2, 2, 1))
|
||||||
|
visibilities = numpy.ones((2, 2))
|
||||||
|
# ----TEST
|
||||||
|
source_fluxes = estimate_sources_flux(visibilities, pointing_matrix)
|
||||||
|
expected = numpy.ones((1))
|
||||||
|
assert_almost_equal(source_fluxes, expected)
|
||||||
|
|
||||||
|
|
||||||
|
def test_estimate_model_visibilities():
|
||||||
|
# ----TEST DATA
|
||||||
|
source_position = numpy.zeros((1, 3))
|
||||||
|
visibilities = numpy.ones((2, 2))
|
||||||
|
baselines = numpy.zeros((2, 2, 3))
|
||||||
|
baselines[0, 1, :] = [1, 0, 0]
|
||||||
|
baselines[1, 0, :] = [1, 0, 0]
|
||||||
|
# ----TEST
|
||||||
|
model_visibilities = estimate_model_visibilities(source_position, visibilities, baselines, 1)
|
||||||
|
assert_almost_equal(visibilities, model_visibilities)
|
||||||
|
|
||||||
|
|
||||||
|
def test_self_cal_zero_residual():
|
||||||
|
# ----TEST DATA
|
||||||
|
source_position = numpy.zeros((1, 3))
|
||||||
|
visibilities = numpy.ones((2, 2))
|
||||||
|
baselines = numpy.zeros((2, 2, 3))
|
||||||
|
baselines[0, 1, :] = [1, 0, 0]
|
||||||
|
baselines[1, 0, :] = [1, 0, 0]
|
||||||
|
# ----TEST
|
||||||
|
calibrated_model, _ = self_cal(visibilities, source_position, baselines, 1)
|
||||||
|
assert_almost_equal(calibrated_model, visibilities)
|
Loading…
Reference in New Issue