def test_phase_rotation(self): self.vis = create_visibility( self.lowcore, self.times, self.frequency, channel_bandwidth=self.channel_bandwidth, phasecentre=self.phasecentre, weight=1.0, polarisation_frame=PolarisationFrame("stokesIQUV")) self.vismodel = predict_skycomponent_visibility(self.vis, self.comp) # Predict visibilities with new phase centre independently ha_diff = -(self.compabsdirection.ra - self.phasecentre.ra).to( u.rad).value vispred = create_visibility( self.lowcore, self.times + ha_diff, self.frequency, channel_bandwidth=self.channel_bandwidth, phasecentre=self.compabsdirection, weight=1.0, polarisation_frame=PolarisationFrame("stokesIQUV")) vismodel2 = predict_skycomponent_visibility(vispred, self.comp) # Should yield the same results as rotation rotatedvis = phaserotate_visibility( self.vismodel, newphasecentre=self.compabsdirection, tangent=False) assert_allclose(rotatedvis.vis, vismodel2.vis, rtol=1e-7) assert_allclose(rotatedvis.uvw, vismodel2.uvw, rtol=1e-7)
def ingest_visibility(self, freq=None, chan_width=None, times=None, reffrequency=None, add_errors=False, block=True): if freq is None: freq = [1e8] if times is None: ntimes = 5 times = numpy.linspace(-numpy.pi / 3.0, numpy.pi / 3.0, ntimes) if chan_width is None: chan_width = [1e6] if reffrequency is None: reffrequency = [1e8] lowcore = create_named_configuration('LOWBD2-CORE') frequency = numpy.array([freq]) channel_bandwidth = numpy.array([chan_width]) phasecentre = SkyCoord(ra=+180.0 * u.deg, dec=-60.0 * u.deg, frame='icrs', equinox='J2000') if block: vt = create_blockvisibility(lowcore, times, frequency, channel_bandwidth=channel_bandwidth, weight=1.0, phasecentre=phasecentre, polarisation_frame=PolarisationFrame("stokesI")) else: vt = create_visibility(lowcore, times, frequency, channel_bandwidth=channel_bandwidth, weight=1.0, phasecentre=phasecentre, polarisation_frame=PolarisationFrame("stokesI")) cellsize = 0.001 model = create_image_from_visibility(vt, npixel=self.npixel, cellsize=cellsize, npol=1, frequency=reffrequency, phasecentre=phasecentre, polarisation_frame=PolarisationFrame("stokesI")) flux = numpy.array([[100.0]]) facets = 4 rpix = model.wcs.wcs.crpix - 1.0 spacing_pixels = self.npixel // facets centers = [-1.5, -0.5, 0.5, 1.5] comps = list() for iy in centers: for ix in centers: p = int(round(rpix[0] + ix * spacing_pixels * numpy.sign(model.wcs.wcs.cdelt[0]))), \ int(round(rpix[1] + iy * spacing_pixels * numpy.sign(model.wcs.wcs.cdelt[1]))) sc = pixel_to_skycoord(p[0], p[1], model.wcs, origin=1) comp = create_skycomponent(flux=flux, frequency=frequency, direction=sc, polarisation_frame=PolarisationFrame("stokesI")) comps.append(comp) if block: predict_skycomponent_blockvisibility(vt, comps) else: predict_skycomponent_visibility(vt, comps) insert_skycomponent(model, comps) self.model = copy_image(model) self.empty_model = create_empty_image_like(model) export_image_to_fits(model, '%s/test_pipeline_bags_model.fits' % self.dir) if add_errors: # These will be the same for all calls numpy.random.seed(180555) gt = create_gaintable_from_blockvisibility(vt) gt = simulate_gaintable(gt, phase_error=1.0, amplitude_error=0.0) vt = apply_gaintable(vt, gt) return vt
def test_invert_2d(self): # Test if the 2D invert works with w set to zero # Set w=0 so that the two-dimensional transform should agree exactly with the model. # Good check on the grid correction in the vis->image direction self.actualSetUp() self.componentvis = create_visibility( self.lowcore, self.times, self.frequency, channel_bandwidth=self.channel_bandwidth, phasecentre=self.phasecentre, weight=1.0, polarisation_frame=self.vis_pol) self.componentvis.data['uvw'][:, 2] = 0.0 self.componentvis.data['vis'] *= 0.0 # Predict the visibility using direct evaluation for comp in self.components: predict_skycomponent_visibility(self.componentvis, comp) dirty2d = create_empty_image_like(self.model) dirty2d, sumwt = invert_2d(self.componentvis, dirty2d, **self.params) export_image_to_fits( dirty2d, '%s/test_imaging_functions_invert_2d_dirty.fits' % self.dir) self._checkcomponents(dirty2d)
def calibrate_visibility(vt: Visibility, model: Image = None, components=None, predict=predict_2d, **kwargs) -> Visibility: """ calibrate Visibility with respect to model and optionally components :param vt: Visibility :param model: Model image :param components: Sky components :return: Calibrated visibility """ assert model is not None or components is not None, "calibration requires a model or skycomponents" vtpred = copy_visibility(vt, zero=True) if model is not None: vtpred = predict(vtpred, model, **kwargs) if components is not None: vtpred = predict_skycomponent_visibility(vtpred, components) else: vtpred = predict_skycomponent_visibility(vtpred, components) bvt = decoalesce_visibility(vt) bvtpred = decoalesce_visibility(vtpred) gt = solve_gaintable(bvt, bvtpred, **kwargs) bvt = apply_gaintable(bvt, gt, inverse=get_parameter(kwargs, "inverse", False)) return convert_blockvisibility_to_visibility(bvt)
def ingest_visibility(self, freq=1e8, chan_width=1e6, times=None, reffrequency=None, add_errors=False): if times is None: times = (numpy.pi / 12.0) * numpy.linspace(-3.0, 3.0, 5) if reffrequency is None: reffrequency = [1e8] lowcore = create_named_configuration('LOWBD2-CORE') frequency = numpy.array([freq]) channel_bandwidth = numpy.array([chan_width]) phasecentre = SkyCoord(ra=+180.0 * u.deg, dec=-60.0 * u.deg, frame='icrs', equinox='J2000') vt = create_visibility(lowcore, times, frequency, channel_bandwidth=channel_bandwidth, weight=1.0, phasecentre=phasecentre, polarisation_frame=PolarisationFrame("stokesI")) cellsize = 0.001 model = create_image_from_visibility( vt, npixel=self.npixel, cellsize=cellsize, npol=1, frequency=reffrequency, phasecentre=phasecentre, polarisation_frame=PolarisationFrame("stokesI")) flux = numpy.array([[100.0]]) facets = 4 rpix = model.wcs.wcs.crpix spacing_pixels = self.npixel // facets centers = [-1.5, -0.5, 0.5, 1.5] comps = list() for iy in centers: for ix in centers: p = int(round(rpix[0] + ix * spacing_pixels * numpy.sign(model.wcs.wcs.cdelt[0]))), \ int(round(rpix[1] + iy * spacing_pixels * numpy.sign(model.wcs.wcs.cdelt[1]))) sc = pixel_to_skycoord(p[0], p[1], model.wcs, origin=0) comp = create_skycomponent( flux=flux, frequency=frequency, direction=sc, polarisation_frame=PolarisationFrame("stokesI")) comps.append(comp) predict_skycomponent_visibility(vt, comps) insert_skycomponent(model, comps) self.model = copy_image(model) export_image_to_fits(model, '%s/test_bags_model.fits' % (self.results_dir)) return vt
def sagecal_fit_gaintable(evis, theta, gain=0.1, niter=3, tol=1e-3, **kwargs): """Fit a gaintable to a visibility i.e. A13 This is the update to the gain part of the window :param evis: :param theta: :param kwargs: :return: """ previous_gt = copy_gaintable(theta[1]) gt = copy_gaintable(theta[1]) model_vis = copy_visibility(evis, zero=True) model_vis = predict_skycomponent_visibility(model_vis, theta[0]) gt = solve_gaintable(evis, model_vis, gt=gt, niter=niter, phase_only=True, gain=0.5, tol=1e-4, **kwargs) gt.data['gain'][...] = gain * gt.data['gain'][...] + \ (1 - gain) * previous_gt.data['gain'][...] gt.data['gain'][...] /= numpy.abs(previous_gt.data['gain'][...]) return gt
def test_phase_rotation_identity(self): self.vis = create_visibility( self.lowcore, self.times, self.frequency, channel_bandwidth=self.channel_bandwidth, phasecentre=self.phasecentre, weight=1.0, polarisation_frame=PolarisationFrame("stokesIQUV")) self.vismodel = predict_skycomponent_visibility(self.vis, self.comp) newphasecenters = [ SkyCoord(182, -35, unit=u.deg), SkyCoord(182, -30, unit=u.deg), SkyCoord(177, -30, unit=u.deg), SkyCoord(176, -35, unit=u.deg), SkyCoord(216, -35, unit=u.deg), SkyCoord(180, -70, unit=u.deg) ] for newphasecentre in newphasecenters: # Phase rotating back should not make a difference original_vis = self.vismodel.vis original_uvw = self.vismodel.uvw rotatedvis = phaserotate_visibility(phaserotate_visibility( self.vismodel, newphasecentre, tangent=False), self.phasecentre, tangent=False) assert_allclose(rotatedvis.uvw, original_uvw, rtol=1e-7) assert_allclose(rotatedvis.vis, original_vis, rtol=1e-7)
def test_visibilitysum(self): self.vis = create_visibility(self.lowcore, self.times, self.frequency, channel_bandwidth=self.channel_bandwidth, phasecentre=self.phasecentre, weight=1.0, polarisation_frame=PolarisationFrame("stokesIQUV")) self.vismodel = predict_skycomponent_visibility(self.vis, self.comp) # Sum the visibilities in the correct_visibility direction. This is limited by numerical precision summedflux, weight = sum_visibility(self.vismodel, self.compreldirection) assert_allclose(self.flux, summedflux, rtol=1e-7)
def test_sum_visibility(self): self.vis = create_visibility(self.lowcore, self.times, self.frequency, channel_bandwidth=self.channel_bandwidth, phasecentre=self.phasecentre, polarisation_frame=PolarisationFrame("linear"), weight=1.0) self.vis = predict_skycomponent_visibility(self.vis, self.comp) flux, weight = sum_visibility(self.vis, self.comp.direction) assert numpy.max(numpy.abs(flux - self.flux)) < 1e-7
def test_qa(self): self.vis = create_visibility(self.lowcore, self.times, self.frequency, channel_bandwidth=self.channel_bandwidth, phasecentre=self.phasecentre, weight=1.0, polarisation_frame=PolarisationFrame("stokesIQUV")) self.vismodel = predict_skycomponent_visibility(self.vis, self.comp) qa = qa_visibility(self.vis, context='test_qa') self.assertAlmostEqual(qa.data['maxabs'], 100.0, 7) self.assertAlmostEqual(qa.data['medianabs'], 11.0, 7) assert qa.context == 'test_qa'
def test_predict_2d(self): # Test if the 2D prediction works # # Set w=0 so that the two-dimensional transform should agree exactly with the component transform. # Good check on the grid correction in the image->vis direction # Set all w to zero self.actualSetUp() self.componentvis = create_visibility( self.lowcore, self.times, self.frequency, channel_bandwidth=self.channel_bandwidth, phasecentre=self.phasecentre, weight=1.0) self.componentvis.data['uvw'][:, 2] = 0.0 # Predict the visibility using direct evaluation predict_skycomponent_visibility(self.componentvis, self.components) self.modelvis = create_visibility( self.lowcore, self.times, self.frequency, channel_bandwidth=self.channel_bandwidth, phasecentre=self.phasecentre, weight=1.0, polarisation_frame=self.vis_pol) self.modelvis.data['uvw'][:, 2] = 0.0 predict_2d(self.modelvis, self.model, **self.params) self.residualvis = create_visibility( self.lowcore, self.times, self.frequency, channel_bandwidth=self.channel_bandwidth, phasecentre=self.phasecentre, weight=1.0, polarisation_frame=self.vis_pol) self.residualvis.data['uvw'][:, 2] = 0.0 self.residualvis.data[ 'vis'] = self.modelvis.data['vis'] - self.componentvis.data['vis'] self._checkdirty(self.residualvis, 'test_predict_2d', fluxthreshold=4.0)
def test_insert_skycomponent_dft(self): sc = create_skycomponent( direction=self.phasecentre, flux=numpy.array([[1.0]]), frequency=self.frequency, polarisation_frame=PolarisationFrame('stokesI')) self.vis.data['vis'][...] = 0.0 self.vis = predict_skycomponent_visibility(self.vis, sc) im, sumwt = invert_2d(self.vis, self.model) export_image_to_fits(im, '%s/test_skycomponent_dft.fits' % self.dir) assert numpy.max(numpy.abs(self.vis.vis.imag)) < 1e-3
def test_invert_2d(self): # Test if the 2D invert works with w set to zero # Set w=0 so that the two-dimensional transform should agree exactly with the model. # Good check on the grid correction in the vis->image direction self.actualSetUp() self.componentvis.data['uvw'][:, 2] = 0.0 self.componentvis.data['vis'] *= 0.0 # Predict the visibility using direct evaluation for comp in self.components: predict_skycomponent_visibility(self.componentvis, comp) dirty2d = create_empty_image_like(self.model) dirty2d, sumwt = invert_2d(self.componentvis, dirty2d, **self.params) export_image_to_fits( dirty2d, '%s/test_imaging_functions_invert_2d_dirty.fits' % self.dir) self._checkcomponents(dirty2d)
def make_e(vis, calskymodel, evis_all): # Return the estep for a given skymodel evis = copy_visibility(vis) tvis = copy_visibility(vis, zero=True) tvis = predict_skycomponent_visibility(tvis, calskymodel[0].components) tvis = apply_gaintable(tvis, calskymodel[1]) # E step is the data model for a window plus the difference between the observed data # and the summed data models or, put another way, its the observed data minus the # summed visibility for all other windows evis.data['vis'][...] = tvis.data['vis'][...] + vis.data['vis'][ ...] - evis_all.data['vis'][...] return evis
def test_phase_rotation_inverse(self): self.vis = create_visibility(self.lowcore, self.times, self.frequency, channel_bandwidth=self.channel_bandwidth, phasecentre=self.phasecentre, weight=1.0, polarisation_frame=PolarisationFrame("stokesIQUV")) self.vismodel = predict_skycomponent_visibility(self.vis, self.comp) there = SkyCoord(ra=+250.0 * u.deg, dec=-60.0 * u.deg, frame='icrs', equinox='J2000') # Phase rotating back should not make a difference original_vis = self.vismodel.vis original_uvw = self.vismodel.uvw rotatedvis = phaserotate_visibility(phaserotate_visibility(self.vismodel, there, tangent=False, inverse=True), self.phasecentre, tangent=False, inverse=True) assert_allclose(rotatedvis.uvw, original_uvw, rtol=1e-7) assert_allclose(rotatedvis.vis, original_vis, rtol=1e-7)
def skymodel_cal_e_step(vis: BlockVisibility, evis_all: BlockVisibility, calskymodel, **kwargs): """Calculates E step in equation A12 This is the data model for this window plus the difference between observed data and summed data models :param evis_all: Sum data models :param csm: csm element being fit :param kwargs: :return: Data model (i.e. visibility) for this csm """ evis = copy_visibility(evis_all) tvis = copy_visibility(vis, zero=True) tvis = predict_skycomponent_visibility(tvis, calskymodel[0].components) tvis = apply_gaintable(tvis, calskymodel[1]) evis.data['vis'][...] = tvis.data['vis'][...] + vis.data['vis'][...] - evis_all.data['vis'][...] return evis
def spectral_line_imaging(vis: Visibility, model: Image, continuum_model: Image = None, continuum_components=None, predict=predict_2d, invert=invert_2d, deconvolve_spectral=False, **kwargs) -> (Image, Image, Image): """Spectral line imaging from calibrated (DIE) data A continuum model can be subtracted, and deconvolution is optional. If deconvolve_spectral is True then the solve_image is used to deconvolve. If deconvolve_spectral is False then the residual image after continuum subtraction is calculated :param vis: Visibility :param continuum_model: model continuum image to be subtracted :param continuum_components: mode components to be subtracted :param spectral_model: model spectral image :param predict: Predict fumction e.g. predict_2d :param invert: Invert function e.g. invert_wprojection :return: Residual visibility, spectral model image, spectral residual image """ vis_no_continuum = copy_visibility(vis) if continuum_model is not None: vis_no_continuum = predict(vis_no_continuum, continuum_model, **kwargs) if continuum_components is not None: vis_no_continuum = predict_skycomponent_visibility( vis_no_continuum, continuum_components) vis_no_continuum.data[ 'vis'] = vis.data['vis'] - vis_no_continuum.data['vis'] if deconvolve_spectral: log.info( "spectral_line_imaging: Deconvolving continuum subtracted visibility" ) vis_no_continuum, spectral_model, spectral_residual = solve_image( vis_no_continuum, model, **kwargs) else: log.info( "spectral_line_imaging: Making dirty image from continuum subtracted visibility" ) spectral_model, spectral_residual = \ invert(vis_no_continuum, model, **kwargs) return vis_no_continuum, spectral_model, spectral_residual
def test_fit_visibility(self): # Sum the visibilities in the correct_visibility direction. This is limited by numerical precision methods = ['CG', 'BFGS', 'Powell', 'trust-ncg', 'trust-exact', 'trust-krylov'] for method in methods: self.actualSetup() self.vis = create_visibility(self.lowcore, self.times, self.frequency, channel_bandwidth=self.channel_bandwidth, phasecentre=self.phasecentre, weight=1.0, polarisation_frame=PolarisationFrame("stokesI")) self.vismodel = predict_skycomponent_visibility(self.vis, self.comp) initial_comp = Skycomponent(direction=self.comp_start_direction, frequency=self.frequency, flux=2.0 * self.flux, polarisation_frame=PolarisationFrame("stokesI")) sc, res = fit_visibility(self.vismodel, initial_comp, niter=200, tol=1e-5, method=method, verbose=False) # print(method, res) assert sc.direction.separation(self.comp_actual_direction).to('rad').value < 1e-6, \ sc.direction.separation(self.comp_actual_direction).to('rad')
def actualSetup(self, sky_pol_frame='stokesIQUV', data_pol_frame='linear', f=None, vnchan=3): self.lowcore = create_named_configuration('LOWBD2-CORE') self.times = (numpy.pi / 43200.0) * numpy.linspace(0.0, 30.0, 3) self.frequency = numpy.linspace(1.0e8, 1.1e8, vnchan) self.channel_bandwidth = numpy.array( vnchan * [self.frequency[1] - self.frequency[0]]) if f is None: f = [100.0, 50.0, -10.0, 40.0] if sky_pol_frame == 'stokesI': f = [100.0] self.flux = numpy.outer( numpy.array( [numpy.power(freq / 1e8, -0.7) for freq in self.frequency]), f) # The phase centre is absolute and the component is specified relative (for now). # This means that the component should end up at the position phasecentre+compredirection self.phasecentre = SkyCoord(ra=+180.0 * u.deg, dec=-35.0 * u.deg, frame='icrs', equinox='J2000') self.compabsdirection = SkyCoord(ra=+181.0 * u.deg, dec=-35.0 * u.deg, frame='icrs', equinox='J2000') self.comp = Skycomponent( direction=self.compabsdirection, frequency=self.frequency, flux=self.flux, polarisation_frame=PolarisationFrame(sky_pol_frame)) self.vis = create_blockvisibility( self.lowcore, self.times, self.frequency, phasecentre=self.phasecentre, channel_bandwidth=self.channel_bandwidth, weight=1.0, polarisation_frame=PolarisationFrame(data_pol_frame)) self.vis = predict_skycomponent_visibility(self.vis, self.comp)
def sagecal_e_all(vis: BlockVisibility, thetas, **kwargs): """Calculates E step in equation A12 This is the sum of the data models over all windows :param vis: :param thetas: :param kwargs: :return: """ evis = copy_visibility(vis, zero=True) tvis = copy_visibility(vis, zero=True) for i, theta in enumerate(thetas): tvis.data['vis'][...] = 0.0 tvis = predict_skycomponent_visibility(tvis, theta[0]) tvis = apply_gaintable(tvis, theta[1]) evis.data['vis'][...] += tvis.data['vis'][...] return evis
def skymodel_cal_e_all(vis: BlockVisibility, calskymodels): """Calculates E step in equation A12 This is the sum of the data models over all skymodel :param vis: Visibility :param csm: List of (skymodel, gaintable) tuples :param kwargs: :return: Sum of data models (i.e. a visibility) """ evis = copy_visibility(vis, zero=True) tvis = copy_visibility(vis, zero=True) for csm in calskymodels: tvis.data['vis'][...] = 0.0 tvis = predict_skycomponent_visibility(tvis, csm[0].components) tvis = apply_gaintable(tvis, csm[1]) evis.data['vis'][...] += tvis.data['vis'][...] return evis
def sagecal_e_step(vis: BlockVisibility, evis_all: BlockVisibility, theta, beta=1.0, **kwargs): """Calculates E step in equation A12 This is the data model for this window plus the difference between observed data and summed data models :param vis: :param theta: :param kwargs: :return: """ evis = copy_visibility(evis_all) tvis = copy_visibility(vis, zero=True) tvis = predict_skycomponent_visibility(tvis, theta[0]) tvis = apply_gaintable(tvis, theta[1]) evis.data['vis'][...] = tvis.data['vis'][...] + \ beta * (vis.data['vis'][...] - evis_all.data['vis'][...]) return evis
def skymodel_cal_fit_gaintable(evis, calskymodel, gain=0.1, niter=3, tol=1e-3, **kwargs): """Fit a gaintable to a visibility This is the update to the gain part of the window :param evis: Expected vis for this ssm :param calskymodel: csm element being fit :param gain: Gain in step :param niter: Number of iterations :param kwargs: Gaintable """ previous_gt = copy_gaintable(calskymodel[1]) gt = copy_gaintable(calskymodel[1]) model_vis = copy_visibility(evis, zero=True) model_vis = predict_skycomponent_visibility(model_vis, calskymodel[0].components) gt = solve_gaintable(evis, model_vis, gt=gt, niter=niter, phase_only=True, gain=0.5, tol=1e-4, **kwargs) gt.data['gain'][...] = gain * gt.data['gain'][...] + \ (1 - gain) * previous_gt.data['gain'][...] gt.data['gain'][...] /= numpy.abs(previous_gt.data['gain'][...]) return gt
def spectral_line_imaging(vis: BlockVisibility, model: Image, continuum_model: Image = None, continuum_components=None, context='2d', **kwargs) -> (Image, Image, Image): """Spectral line imaging from calibrated (DIE) data A continuum model can be subtracted, and the residual image deconvolved. :param vis: Visibility :param model: Image specify details of model :param continuum_model: model continuum image to be subtracted :param continuum_components: mode components to be subtracted :param spectral_model: model spectral image :param predict: Predict fumction e.g. predict_2d :param invert: Invert function e.g. invert_wprojection :return: Residual visibility, spectral model image, spectral residual image """ vis_no_continuum = copy_visibility(vis) if continuum_model is not None: vis_no_continuum = predict_function(vis_no_continuum, continuum_model, context=context, **kwargs) if continuum_components is not None: vis_no_continuum = predict_skycomponent_visibility( vis_no_continuum, continuum_components) vis_no_continuum.data[ 'vis'] = vis.data['vis'] - vis_no_continuum.data['vis'] log.info( "spectral_line_imaging: Deconvolving continuum subtracted visibility") return ical(vis_no_continuum.data, model, components=None, context=context, do_selfcal=False, **kwargs)
def test_predict_2d(self): # Test if the 2D prediction works # # Set w=0 so that the two-dimensional transform should agree exactly with the component transform. # Good check on the grid correction in the image->vis direction # Set all w to zero self.actualSetUp() self.componentvis.data['uvw'][:, 2] = 0.0 # Predict the visibility using direct evaluation self.componentvis.data['vis'][...] = 0.0 self.componentvis = predict_skycomponent_visibility( self.componentvis, self.components) self.modelvis = copy_visibility(self.componentvis, zero=True) self.modelvis.data['uvw'][:, 2] = 0.0 self.modelvis = predict_2d(self.modelvis, self.model, **self.params) self.residualvis = copy_visibility(self.componentvis, zero=True) self.residualvis.data['uvw'][:, 2] = 0.0 self.residualvis.data[ 'vis'] = self.modelvis.data['vis'] - self.componentvis.data['vis'] self._checkdirty(self.residualvis, 'predict_2d')
def rcal(vis: BlockVisibility, components, **kwargs) -> GainTable: """ Real-time calibration pipeline. Reads visibilities through a BlockVisibility iterator, calculates model visibilities according to a component-based sky model, and performs calibration solution, writing a gaintable for each chunk of visibilities. :param vis: Visibility or Union(Visibility, Iterable) :param components: Component-based sky model :param kwargs: Parameters :return: gaintable """ if not isinstance(vis, collections.Iterable): vis = [vis] from arl.calibration.solvers import solve_gaintable for ichunk, vischunk in enumerate(vis): vispred = copy_visibility(vischunk, zero=True) vispred = predict_skycomponent_visibility(vispred, components) gt = solve_gaintable(vischunk, vispred, **kwargs) yield gt
def actualSetup(self, sky_pol_frame='stokesIQUV', data_pol_frame='linear'): self.lowcore = create_named_configuration('LOWBD2-CORE') self.times = (numpy.pi / 43200.0) * numpy.arange(0.0, 300.0, 30.0) vnchan = 3 self.frequency = numpy.linspace(1.0e8, 1.1e8, vnchan) self.channel_bandwidth = numpy.array( vnchan * [self.frequency[1] - self.frequency[0]]) # Define the component and give it some spectral behaviour f = numpy.array([100.0, 20.0, -10.0, 1.0]) self.flux = numpy.array([f, 0.8 * f, 0.6 * f]) self.phasecentre = SkyCoord(ra=+180.0 * u.deg, dec=-35.0 * u.deg, frame='icrs', equinox='J2000') self.compabsdirection = SkyCoord(ra=+181.0 * u.deg, dec=-35.0 * u.deg, frame='icrs', equinox='J2000') if sky_pol_frame == 'stokesI': self.flux = self.flux[:, 0][:, numpy.newaxis] self.comp = Skycomponent( direction=self.compabsdirection, frequency=self.frequency, flux=self.flux, polarisation_frame=PolarisationFrame(sky_pol_frame)) self.vis = create_blockvisibility( self.lowcore, self.times, self.frequency, phasecentre=self.phasecentre, channel_bandwidth=self.channel_bandwidth, weight=1.0, polarisation_frame=PolarisationFrame(data_pol_frame)) self.vis = predict_skycomponent_visibility(self.vis, self.comp)
def create_blockvisibility_iterator( config: Configuration, times: numpy.array, frequency: numpy.array, channel_bandwidth, phasecentre: SkyCoord, weight: float = 1, polarisation_frame=PolarisationFrame('stokesI'), integration_time=1.0, number_integrations=1, predict=predict_timeslice, model=None, components=None, phase_error=0.0, amplitude_error=0.0, sleep=0.0, **kwargs): """ Create a sequence of Visibilities and optionally predicting and coalescing This is useful mainly for performing large simulations. Do something like:: vis_iter = create_blockvisibility_iterator(config, times, frequency, channel_bandwidth, phasecentre=phasecentre, weight=1.0, integration_time=30.0, number_integrations=3) for i, vis in enumerate(vis_iter): if i == 0: fullvis = vis else: fullvis = append_visibility(fullvis, vis) :param config: Configuration of antennas :param times: hour angles in radians :param frequency: frequencies (Hz] Shape [nchan] :param weight: weight of a single sample :param phasecentre: phasecentre of observation :param npol: Number of polarizations :param integration_time: Integration time ('auto' or value in s) :param number_integrations: Number of integrations to be created at each time. :param model: Model image to be inserted :param components: Components to be inserted :param sleep_time: Time to sleep between yields :return: Visibility """ for time in times: actualtimes = time + numpy.arange( 0, number_integrations) * integration_time * numpy.pi / 43200.0 bvis = create_blockvisibility(config, actualtimes, frequency=frequency, phasecentre=phasecentre, weight=weight, polarisation_frame=polarisation_frame, integration_time=integration_time, channel_bandwidth=channel_bandwidth) if model is not None: vis = predict(bvis, model, **kwargs) bvis = convert_visibility_to_blockvisibility(vis) if components is not None: bvis = predict_skycomponent_visibility(bvis, components) # Add phase errors if phase_error > 0.0 or amplitude_error > 0.0: gt = create_gaintable_from_blockvisibility(bvis) gt = simulate_gaintable(gt=gt, phase_error=phase_error, amplitude_error=amplitude_error) bvis = apply_gaintable(bvis, gt) import time time.sleep(sleep) yield bvis
def test_peel_skycomponent_blockvisibility(self): df = 1e6 frequency = numpy.array([1e8 - df, 1e8, 1e8 + df]) channel_bandwidth = numpy.array([df, df, df]) # Define the component and give it some spectral behaviour f = numpy.array([100.0, 20.0, -10.0, 1.0]) flux = numpy.array([f, 0.8 * f, 0.6 * f]) phasecentre = SkyCoord(0 * u.deg, -60.0 * u.deg) config = create_named_configuration('LOWBD2-CORE') peeldirection = SkyCoord(+15 * u.deg, -60.0 * u.deg) times = numpy.linspace(-3.0, 3.0, 7) * numpy.pi / 12.0 # Make the visibility vis = create_blockvisibility( config, times, frequency, phasecentre=phasecentre, weight=1.0, polarisation_frame=PolarisationFrame('linear'), channel_bandwidth=channel_bandwidth) vis.data['vis'][...] = 0.0 # First add in the source to be peeled. peel = Skycomponent(direction=peeldirection, frequency=frequency, flux=flux, polarisation_frame=PolarisationFrame("stokesIQUV")) vis = predict_skycomponent_visibility(vis, peel) # Make a gaintable and apply it to the visibility of the peeling source gt = create_gaintable_from_blockvisibility(vis, timeslice='auto') gt = simulate_gaintable(gt, phase_error=0.01, amplitude_error=0.01, timeslice='auto') gt.data['gain'] *= 0.3 vis = apply_gaintable(vis, gt, timeslice='auto') # Now create a plausible field using the GLEAM sources model = create_image_from_visibility( vis, cellsize=0.001, frequency=frequency, polarisation_frame=PolarisationFrame('stokesIQUV')) bm = create_low_test_beam(model=model) sc = create_low_test_skycomponents_from_gleam( flux_limit=1.0, polarisation_frame=PolarisationFrame("stokesIQUV"), frequency=frequency, kind='cubic', phasecentre=phasecentre, radius=0.1) sc = apply_beam_to_skycomponent(sc, bm) # Add in the visibility due to these sources vis = predict_skycomponent_visibility(vis, sc) assert numpy.max(numpy.abs(vis.vis)) > 0.0 # Now we can peel vis, peel_gts = peel_skycomponent_blockvisibility(vis, peel) assert len(peel_gts) == 1 residual = numpy.max(peel_gts[0].residual) assert residual < 0.7, "Peak residual %.6f too large" % (residual) im, sumwt = invert_timeslice(vis, model, timeslice='auto') qa = qa_image(im) assert numpy.abs(qa.data['max'] - 14.2) < 1.0, str(qa)
def ical(block_vis: BlockVisibility, model: Image, components=None, context='2d', controls=None, **kwargs): """ Post observation image, deconvolve, and self-calibrate :param vis: :param model: Model image :param components: Initial components :param context: Imaging context :param controls: Calibration controls dictionary :return: model, residual, restored """ nmajor = get_parameter(kwargs, 'nmajor', 5) log.info("ical: Performing %d major cycles" % nmajor) do_selfcal = get_parameter(kwargs, "do_selfcal", False) if controls is None: controls = create_calibration_controls(**kwargs) # The model is added to each major cycle and then the visibilities are # calculated from the full model vis = convert_blockvisibility_to_visibility(block_vis) block_vispred = copy_visibility(block_vis, zero=True) vispred = convert_blockvisibility_to_visibility(block_vispred) vispred.data['vis'][...] = 0.0 visres = copy_visibility(vispred) vispred = predict_function(vispred, model, context=context, **kwargs) if components is not None: vispred = predict_skycomponent_visibility(vispred, components) if do_selfcal: vis, gaintables = calibrate_function(vis, vispred, 'TGB', controls, iteration=-1) visres.data['vis'] = vis.data['vis'] - vispred.data['vis'] dirty, sumwt = invert_function(visres, model, context=context, **kwargs) log.info("Maximum in residual image is %.6f" % (numpy.max(numpy.abs(dirty.data)))) psf, sumwt = invert_function(visres, model, dopsf=True, context=context, **kwargs) thresh = get_parameter(kwargs, "threshold", 0.0) for i in range(nmajor): log.info("ical: Start of major cycle %d of %d" % (i, nmajor)) cc, res = deconvolve_cube(dirty, psf, **kwargs) model.data += cc.data vispred.data['vis'][...] = 0.0 vispred = predict_function(vispred, model, context=context, **kwargs) if do_selfcal: vis, gaintables = calibrate_function(vis, vispred, 'TGB', controls, iteration=i) visres.data['vis'] = vis.data['vis'] - vispred.data['vis'] dirty, sumwt = invert_function(visres, model, context=context, **kwargs) log.info("Maximum in residual image is %s" % (numpy.max(numpy.abs(dirty.data)))) if numpy.abs(dirty.data).max() < 1.1 * thresh: log.info("ical: Reached stopping threshold %.6f Jy" % thresh) break log.info("ical: End of major cycle") log.info("ical: End of major cycles") restored = restore_cube(model, psf, dirty, **kwargs) return model, dirty, restored