def insert_unittest_errors(vt, seed=180555, amp_errors=None, phase_errors=None): """Simulate gain errors and apply :param vt: :param seed: Random number seed, set to big integer repeat values from run to run :param phase_errors: e.g. {'T': 1.0, 'G': 0.1, 'B': 0.01} :param amp_errors: e.g. {'T': 0.0, 'G': 0.01, 'B': 0.01} :return: """ numpy.random.seed(seed) controls = create_calibration_controls() if amp_errors is None: amp_errors = {'T': 0.0, 'G': 0.01, 'B': 0.01} if phase_errors is None: phase_errors = {'T': 1.0, 'G': 0.1, 'B': 0.01} for c in "TGB": gaintable = \ create_gaintable_from_blockvisibility(vt, timeslice=controls[c]['timeslice']) gaintable = simulate_gaintable( gaintable, timeslice=controls[c]['timeslice'], phase_only=controls[c]['phase_only'], crosspol=controls[c]['shape'] == 'matrix', phase_error=phase_errors[c], amplitude_error=amp_errors[c]) vt = apply_gaintable(vt, gaintable, inverse=True, timeslice=controls[c]['timeslice']) return vt
def core_solve(self, spf, dpf, phase_error=0.1, amplitude_error=0.0, leakage=0.0, phase_only=True, niter=200, crosspol=False, residual_tol=1e-6, f=None, vnchan=3, timeslice='auto'): if f is None: f = [100.0, 50.0, -10.0, 40.0] self.actualSetup(spf, dpf, f=f, vnchan=vnchan) gt = create_gaintable_from_blockvisibility(self.vis, timeslice=timeslice) log.info("Created gain table: %s" % (gaintable_summary(gt))) gt = simulate_gaintable(gt, phase_error=phase_error, amplitude_error=amplitude_error, leakage=leakage) original = copy_visibility(self.vis) vis = apply_gaintable(self.vis, gt) gtsol = solve_gaintable(self.vis, original, phase_only=phase_only, niter=niter, crosspol=crosspol, tol=1e-6) vis = apply_gaintable(vis, gtsol, inverse=True) residual = numpy.max(gtsol.residual) assert residual < residual_tol, "%s %s Max residual = %s" % (spf, dpf, residual) log.debug(qa_gaintable(gt)) assert numpy.max(numpy.abs(gtsol.gain - 1.0)) > 0.1
def create_gaintable_from_screen(vis, sc, screen, height=3e5, vis_slices=None, scale=1.0, **kwargs): """ Create gaintables from a screen calculated using ARatmospy :param vis: :param sc: Sky components for which pierce points are needed :param screen: :param height: Height (in m) of screen above telescope e.g. 3e5 :param scale: Multiply the screen by this factor :return: """ assert isinstance(vis, BlockVisibility) station_locations = vis.configuration.xyz nant = station_locations.shape[0] t2r = numpy.pi / 43200.0 gaintables = [ create_gaintable_from_blockvisibility(vis, **kwargs) for i in sc ] # The time in the Visibility is hour angle in seconds! for iha, rows in enumerate(vis_timeslice_iter(vis, vis_slices=vis_slices)): v = create_visibility_from_rows(vis, rows) ha = numpy.average(v.time) number_bad = 0 number_good = 0 for icomp, comp in enumerate(sc): pp = find_pierce_points(station_locations, (comp.direction.ra.rad + t2r * ha) * u.rad, comp.direction.dec, height=height, phasecentre=vis.phasecentre) scr = numpy.zeros([nant]) for ant in range(nant): pp0 = pp[ant][0:2] worldloc = [pp0[0], pp0[1], ha, 1e8] try: pixloc = screen.wcs.wcs_world2pix([worldloc], 0)[0].astype('int') scr[ant] = scale * screen.data[pixloc[3], pixloc[2], pixloc[1], pixloc[0]] number_good += 1 except: number_bad += 1 scr[ant] = 0.0 gaintables[icomp].gain[iha, :, :, :] = numpy.exp( 1j * scr[:, numpy.newaxis, numpy.newaxis, numpy.newaxis]) gaintables[icomp].phasecentre = comp.direction if number_bad > 0: log.warning( "create_gaintable_from_screen: %d pierce points are inside the screen image" % (number_good)) log.warning( "create_gaintable_from_screen: %d pierce points are outside the screen image" % (number_bad)) return gaintables
def actualSetup(self, vnchan=1, doiso=True, ntimes=5, flux_limit=2.0, zerow=True, fixed=False): nfreqwin = vnchan rmax = 300.0 npixel = 512 cellsize = 0.001 frequency = numpy.linspace(0.8e8, 1.2e8, nfreqwin) if nfreqwin > 1: channel_bandwidth = numpy.array(nfreqwin * [frequency[1] - frequency[0]]) else: channel_bandwidth = [0.4e8] times = numpy.linspace(-numpy.pi / 3.0, numpy.pi / 3.0, ntimes) phasecentre = SkyCoord(ra=-60.0 * u.deg, dec=-60.0 * u.deg, frame='icrs', equinox='J2000') lowcore = create_named_configuration('LOWBD2', rmax=rmax) block_vis = create_blockvisibility( lowcore, times, frequency=frequency, channel_bandwidth=channel_bandwidth, weight=1.0, phasecentre=phasecentre, polarisation_frame=PolarisationFrame("stokesI"), zerow=zerow) block_vis.data['uvw'][..., 2] = 0.0 self.beam = create_image_from_visibility( block_vis, npixel=npixel, frequency=[numpy.average(frequency)], nchan=nfreqwin, channel_bandwidth=[numpy.sum(channel_bandwidth)], cellsize=cellsize, phasecentre=phasecentre) self.components = create_low_test_skycomponents_from_gleam( flux_limit=flux_limit, phasecentre=phasecentre, frequency=frequency, polarisation_frame=PolarisationFrame('stokesI'), radius=npixel * cellsize) self.beam = create_low_test_beam(self.beam) self.components = apply_beam_to_skycomponent(self.components, self.beam, flux_limit=flux_limit) self.vis = copy_visibility(block_vis, zero=True) gt = create_gaintable_from_blockvisibility(block_vis, timeslice='auto') for i, sc in enumerate(self.components): if sc.flux[0, 0] > 10: sc.flux[...] /= 10.0 component_vis = copy_visibility(block_vis, zero=True) gt = simulate_gaintable(gt, amplitude_error=0.0, phase_error=0.1, seed=None) component_vis = predict_skycomponent_visibility(component_vis, sc) component_vis = apply_gaintable(component_vis, gt) self.vis.data['vis'][...] += component_vis.data['vis'][...] # Do an isoplanatic selfcal self.model_vis = copy_visibility(self.vis, zero=True) self.model_vis = predict_skycomponent_visibility( self.model_vis, self.components) if doiso: gt = solve_gaintable(self.vis, self.model_vis, phase_only=True, timeslice='auto') self.vis = apply_gaintable(self.vis, gt, inverse=True) self.model_vis = convert_blockvisibility_to_visibility(self.model_vis) self.model_vis, _, _ = weight_visibility(self.model_vis, self.beam) self.dirty_model, sumwt = invert_function(self.model_vis, self.beam, context='2d') export_image_to_fits(self.dirty_model, "%s/test_skymodel-model_dirty.fits" % self.dir) lvis = convert_blockvisibility_to_visibility(self.vis) lvis, _, _ = weight_visibility(lvis, self.beam) dirty, sumwt = invert_function(lvis, self.beam, context='2d') if doiso: export_image_to_fits( dirty, "%s/test_skymodel-initial-iso-residual.fits" % self.dir) else: export_image_to_fits( dirty, "%s/test_skymodel-initial-noiso-residual.fits" % self.dir) self.skymodels = [ SkyModel(components=[cm], fixed=fixed) for cm in self.components ]
gleam_model, vis_slices=51, context='wstack') #print("np.sum(predicted_vis.data): ", numpy.sum(predicted_vis.data['vis'])) block_vis = convert_visibility_to_blockvisibility(predicted_vis) #print("np.sum(block_vis.data): ", numpy.sum(block_vis.data['vis'])) #print("nchan npol nants ", block_vis.nchan, block_vis.npol, block_vis.nants) #print("uvw", block_vis.uvw, numpy.sum(block_vis.uvw)) #print("vis", block_vis.vis, numpy.sum(block_vis.vis)) #print("weight", block_vis.weight, numpy.sum(block_vis.weight)) #print("time", block_vis.time, numpy.sum(block_vis.time)) #print("integration_time", block_vis.integration_time, numpy.sum(block_vis.integration_time)) #print("nvis, size", block_vis.nvis, block_vis.size()) gt = create_gaintable_from_blockvisibility(block_vis) #print("np.sum(gt.data): ", numpy.sum(gt.data['gain'])) gt = simulate_gaintable(gt, phase_error=1.0) #print("np.sum(gt.data): ", numpy.sum(gt.data['gain'])) blockvis = apply_gaintable(block_vis, gt) #print("np.sum(blockvis.data): ", numpy.sum(blockvis.data['vis'])) model = create_image_from_visibility( block_vis, npixel=npixel, frequency=[numpy.average(frequency)], nchan=1, channel_bandwidth=[numpy.sum(channel_bandwidth)], cellsize=cellsize, phasecentre=phasecentre)
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_2d, 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 corrupt_vis(vis, gt, **kwargs): if gt is None: gt = create_gaintable_from_blockvisibility(vis, **kwargs) gt = simulate_gaintable(gt, **kwargs) return apply_gaintable(vis, gt)
def simulate_gaintable_from_voltage_patterns(vis, sc, vp_list, vp_coeffs, vis_slices=None, order=3, use_radec=False, **kwargs): """ Create gaintables for a set of zernikes :param vis: :param sc: Sky components for which pierce points are needed :param vp: List of Voltage patterns in AZELGEO frame :param vp_coeffs: Fractional contribution [nants, nvp] :param order: order of spline (default is 3) :return: """ ntimes, nant = vis.vis.shape[0:2] vp_coeffs = numpy.array(vp_coeffs) gaintables = [ create_gaintable_from_blockvisibility(vis, **kwargs) for i in sc ] if not use_radec: assert isinstance(vis, BlockVisibility) assert vis.configuration.mount[ 0] == 'azel', "Mount %s not supported yet" % vis.configuration.mount[ 0] # The time in the Visibility is hour angle in seconds! number_bad = 0 number_good = 0 # Cache the splines, one per voltage pattern real_splines = list() imag_splines = list() for ivp, vp in enumerate(vp_list): assert vp.wcs.wcs.ctype[0] == 'AZELGEO long', vp.wcs.wcs.ctype[0] assert vp.wcs.wcs.ctype[1] == 'AZELGEO lati', vp.wcs.wcs.ctype[1] nchan, npol, ny, nx = vp.data.shape real_splines.append( RectBivariateSpline(range(ny), range(nx), vp.data[0, 0, ...].real, kx=order, ky=order)) imag_splines.append( RectBivariateSpline(range(ny), range(nx), vp.data[0, 0, ...].imag, kx=order, ky=order)) latitude = vis.configuration.location.lat.rad r2d = 180.0 / numpy.pi s2r = numpy.pi / 43200.0 # For each hourangle, we need to calculate the location of a component # in AZELGEO. With that we can then look up the relevant gain from the # voltage pattern for iha, rows in enumerate( vis_timeslice_iter(vis, vis_slices=vis_slices)): v = create_visibility_from_rows(vis, rows) ha = numpy.average(v.time) har = s2r * ha # Calculate the az el for this hourangle and the phasecentre declination azimuth_centre, elevation_centre = hadec_to_azel( har, vis.phasecentre.dec.rad, latitude) for icomp, comp in enumerate(sc): antgain = numpy.zeros([nant], dtype='complex') # Calculate the location of the component in AZELGEO, then add the pointing offset # for each antenna hacomp = comp.direction.ra.rad - vis.phasecentre.ra.rad + har deccomp = comp.direction.dec.rad azimuth_comp, elevation_comp = hadec_to_azel( hacomp, deccomp, latitude) for ant in range(nant): for ivp, vp in enumerate(vp_list): nchan, npol, ny, nx = vp.data.shape wcs_azel = vp.wcs.deepcopy() az_comp = azimuth_centre * r2d el_comp = elevation_centre * r2d # We use WCS sensible coordinate handling by labelling the axes misleadingly wcs_azel.wcs.crval[0] = az_comp wcs_azel.wcs.crval[1] = el_comp wcs_azel.wcs.ctype[0] = 'RA---SIN' wcs_azel.wcs.ctype[1] = 'DEC--SIN' worldloc = [ azimuth_comp * r2d, elevation_comp * r2d, vp.wcs.wcs.crval[2], vp.wcs.wcs.crval[3] ] try: pixloc = wcs_azel.sub(2).wcs_world2pix( [worldloc[:2]], 1)[0] assert pixloc[0] > 2 assert pixloc[0] < nx - 3 assert pixloc[1] > 2 assert pixloc[1] < ny - 3 gain = real_splines[ivp].ev(pixloc[1], pixloc[0]) \ + 1j * imag_splines[ivp](pixloc[1], pixloc[0]) antgain[ant] += vp_coeffs[ant, ivp] * gain number_good += 1 except: number_bad += 1 antgain[ant] = 0.0 antgain[ant] = 1.0 / antgain[ant] gaintables[icomp].gain[iha, :, :, :] = antgain[:, numpy.newaxis, numpy.newaxis, numpy.newaxis] gaintables[icomp].phasecentre = comp.direction else: assert isinstance(vis, BlockVisibility) number_bad = 0 number_good = 0 # Cache the splines, one per voltage pattern real_splines = list() imag_splines = list() for ivp, vp in enumerate(vp_list): nchan, npol, ny, nx = vp.data.shape real_splines.append( RectBivariateSpline(range(ny), range(nx), vp.data[0, 0, ...].real, kx=order, ky=order)) imag_splines.append( RectBivariateSpline(range(ny), range(nx), vp.data[0, 0, ...].imag, kx=order, ky=order)) for iha, rows in enumerate( vis_timeslice_iter(vis, vis_slices=vis_slices)): # The time in the Visibility is hour angle in seconds! r2d = 180.0 / numpy.pi # For each hourangle, we need to calculate the location of a component # in AZELGEO. With that we can then look up the relevant gain from the # voltage pattern v = create_visibility_from_rows(vis, rows) ha = numpy.average(v.time) for icomp, comp in enumerate(sc): antgain = numpy.zeros([nant], dtype='complex') antwt = numpy.zeros([nant]) ra_comp = comp.direction.ra.rad dec_comp = comp.direction.dec.rad for ant in range(nant): for ivp, vp in enumerate(vp_list): assert vp.wcs.wcs.ctype[ 0] == 'RA---SIN', vp.wcs.wcs.ctype[0] assert vp.wcs.wcs.ctype[ 1] == 'DEC--SIN', vp.wcs.wcs.ctype[1] worldloc = [ ra_comp * r2d, dec_comp * r2d, vp.wcs.wcs.crval[2], vp.wcs.wcs.crval[3] ] nchan, npol, ny, nx = vp.data.shape try: pixloc = vp.wcs.sub(2).wcs_world2pix( [worldloc[:2]], 1)[0] assert pixloc[0] > 2 assert pixloc[0] < nx - 3 assert pixloc[1] > 2 assert pixloc[1] < ny - 3 gain = real_splines[ivp].ev(pixloc[1], pixloc[0]) \ + 1j * imag_splines[ivp](pixloc[1], pixloc[0]) antgain[ant] += vp_coeffs[ant, ivp] * gain antwt[ant] = 1.0 number_good += 1 except: number_bad += 1 antgain[ant] = 1e15 antwt[ant] = 0.0 antgain[ant] = 1.0 / antgain[ant] gaintables[icomp].gain[ iha, :, :, :] = antgain[:, numpy.newaxis, numpy.newaxis, numpy.newaxis] gaintables[icomp].weight[ iha, :, :, :] = antwt[:, numpy.newaxis, numpy.newaxis, numpy.newaxis] gaintables[icomp].phasecentre = comp.direction if number_bad > 0: log.warning( "simulate_gaintable_from_voltage_patterns: %d points are inside the voltage pattern image" % (number_good)) log.warning( "simulate_gaintable_from_voltage_patterns: %d points are outside the voltage pattern image" % (number_bad)) return gaintables
def create_calskymodel(vis, skymodel): gt = create_gaintable_from_blockvisibility(vis, **kwargs) return (copy_skymodel(skymodel), copy_gaintable(gt))
def create_gaintable_from_pointingtable(vis, sc, pt, vp, vis_slices=None, scale=1.0, order=3, **kwargs): """ Create gaintables from a pointing table :param vis: :param sc: Sky components for which pierce points are needed :param pt: Pointing table :param vp: Voltage pattern :param scale: Multiply the screen by this factor :param order: order of spline (default is 3) :return: """ assert isinstance(vis, BlockVisibility) nant = vis.vis.shape[1] gaintables = [ create_gaintable_from_blockvisibility(vis, **kwargs) for i in sc ] nchan, npol, ny, nx = vp.data.shape real_spline = RectBivariateSpline(range(ny), range(nx), vp.data[0, 0, ...].real, kx=order, ky=order) imag_spline = RectBivariateSpline(range(ny), range(nx), vp.data[0, 0, ...].imag, kx=order, ky=order) # The time in the Visibility is hour angle in seconds! for iha, rows in enumerate(vis_timeslice_iter(vis, vis_slices=vis_slices)): v = create_visibility_from_rows(vis, rows) ha = numpy.average(v.time) pt_rows = (pt.time == ha) pointing_ha = pt.pointing[pt_rows] number_bad = 0 number_good = 0 r2d = 180.0 / numpy.pi for icomp, comp in enumerate(sc): antgain = numpy.zeros([nant], dtype='complex') for ant in range(nant): worldloc = [ float( (comp.direction.ra.rad + pointing_ha[0, ant, 0, 0, 0]) * r2d), float( (comp.direction.dec.rad + pointing_ha[0, ant, 0, 0, 1]) * r2d), vp.wcs.wcs.crval[2], vp.wcs.wcs.crval[3] ] try: pixloc = vp.wcs.wcs_world2pix([worldloc], 0)[0][0:2] gain = real_spline.ev( pixloc[1], pixloc[0]) + 1j * imag_spline(pixloc[1], pixloc[0]) antgain[ant] = 1.0 / (scale * gain) number_good += 1 except: number_bad += 1 antgain[ant] = 0.0 gaintables[icomp].gain[iha, :, :, :] = antgain[:, numpy.newaxis, numpy.newaxis, numpy.newaxis] gaintables[icomp].phasecentre = comp.direction if number_bad > 0: log.warning( "create_gaintable_from_pointingtable: %d points are inside the voltage pattern image" % (number_good)) log.warning( "create_gaintable_from_pointingtable: %d points are outside the voltage pattern image" % (number_bad)) return gaintables
def ingest_visibility(self, freq=None, chan_width=None, times=None, add_errors=False, block=True, bandpass=False): if freq is None: freq = [1e8] if chan_width is None: chan_width = [1e6] if times is None: times = (numpy.pi / 12.0) * numpy.linspace(-3.0, 3.0, 5) lowcore = create_named_configuration('LOWBD2', rmax=750.0) 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=frequency, phasecentre=phasecentre, polarisation_frame=PolarisationFrame("stokesI")) nchan = len(self.frequency) flux = numpy.array(nchan * [[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( direction=sc, flux=flux, frequency=frequency, polarisation_frame=PolarisationFrame("stokesI")) comps.append(comp) if block: predict_skycomponent_visibility(vt, comps) else: predict_skycomponent_visibility(vt, comps) insert_skycomponent(model, comps) self.comps = comps self.model = copy_image(model) self.empty_model = create_empty_image_like(model) export_image_to_fits( model, '%s/test_pipeline_functions_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) if bandpass: bgt = create_gaintable_from_blockvisibility(vt, timeslice=1e5) bgt = simulate_gaintable(bgt, phase_error=0.01, amplitude_error=0.01, smooth_channels=4) vt = apply_gaintable(vt, bgt) return vt