def copy_skycomponent(sc): """Copy a sky component of Iterable of skycomponents :param sc: :return: """ single = not isinstance(sc, collections.abc.Iterable) if single: return Skycomponent( direction=sc.direction, frequency=sc.frequency, name=sc.name, flux=sc.flux, shape=sc.shape, params=sc.params, polarisation_frame=sc.polarisation_frame) else: return [Skycomponent( direction=s.direction, frequency=s.frequency, name=s.name, flux=s.flux, shape=s.shape, params=s.params, polarisation_frame=s.polarisation_frame) for s in sc]
def setUp(self): from rascil.data_models.parameters import rascil_path self.dir = rascil_path('test_results/') self.midcore = create_named_configuration('MID', rmax=3000.0) self.times = (numpy.pi / 43200.0) * numpy.arange(0.0, 300.0, 100.0) self.frequency = numpy.linspace(1.0e9, 1.1e9, 3) self.channel_bandwidth = numpy.array([1e7, 1e7, 1e7]) # 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]) # 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)
def setUp(self): self.lowcore = create_named_configuration('LOWBD2-CORE') self.times = (numpy.pi / 43200.0) * numpy.arange(0.0, 300.0, 30.0) self.frequency = numpy.linspace(1.0e8, 1.1e8, 3) self.channel_bandwidth = numpy.array([1e7, 1e7, 1e7]) # 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.polarisation_frame = PolarisationFrame("linear") # 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') pcof = self.phasecentre.skyoffset_frame() self.compreldirection = self.compabsdirection.transform_to(pcof) self.comp = Skycomponent(direction=self.compreldirection, frequency=self.frequency, flux=self.flux)
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 = dft_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) assert sc.direction.separation(self.comp_actual_direction).to('rad').value < 1e-6, \ sc.direction.separation(self.comp_actual_direction).to('rad')
def test_phase_rotation_stokesi(self): # Define the component and give it some spectral behaviour f = numpy.array([100.0]) self.flux = numpy.array([f, 0.8 * f, 0.6 * 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') pcof = self.phasecentre.skyoffset_frame() self.compreldirection = self.compabsdirection.transform_to(pcof) self.comp = Skycomponent(direction=self.compreldirection, frequency=self.frequency, flux=self.flux, polarisation_frame=PolarisationFrame("stokesI")) 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) # 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("stokesI")) 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=3e-6) assert_allclose(rotatedvis.uvw, vismodel2.uvw, rtol=3e-6)
def actualSetup(self): self.lowcore = create_named_configuration('LOWBD2-CORE') self.times = (numpy.pi / 43200.0) * numpy.arange(0.0, 300.0, 30.0) self.times = [0.0] self.frequency = numpy.linspace(1.0e8, 1.1e8, 1) self.channel_bandwidth = numpy.array([1e7]) # 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]) f = numpy.array([100.0]) self.flux = numpy.array([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.comp_actual_direction = SkyCoord(ra=+180.2 * u.deg, dec=-35.1 * u.deg, frame='icrs', equinox='J2000') self.comp_start_direction = SkyCoord(ra=+180.0 * u.deg, dec=-35.0 * u.deg, frame='icrs', equinox='J2000') self.comp = Skycomponent( direction=self.comp_actual_direction, frequency=self.frequency, flux=self.flux, polarisation_frame=PolarisationFrame("stokesI"))
def test_create_vis_iter_with_model(self): model = create_test_image(canonical=True, cellsize=0.001, frequency=self.frequency, phasecentre=self.phasecentre) comp = Skycomponent(direction=self.phasecentre, frequency=self.frequency, flux=self.flux, polarisation_frame=PolarisationFrame('stokesI')) vis_iter = create_blockvisibility_iterator( self.config, self.times, self.frequency, channel_bandwidth=self.channel_bandwidth, phasecentre=self.phasecentre, weight=1.0, polarisation_frame=PolarisationFrame('stokesI'), integration_time=30.0, number_integrations=3, model=model, components=comp) fullvis = None totalnvis = 0 for i, bvis in enumerate(vis_iter): assert bvis.phasecentre == self.phasecentre assert bvis.nvis if i == 0: fullvis = bvis totalnvis = bvis.nvis else: fullvis = append_visibility(fullvis, bvis) totalnvis += bvis.nvis assert fullvis.nvis == totalnvis
def test_simulate_gaintable_from_voltage_patterns(self): numpy.random.seed(18051955) offset_phasecentre = SkyCoord(ra=+15.0 * u.deg, dec=-44.58 * u.deg, frame='icrs', equinox='J2000') component = [Skycomponent(frequency=self.frequency, direction=offset_phasecentre, polarisation_frame=PolarisationFrame("stokesI"), flux=[[1.0]])] key_nolls = [3, 5, 6, 7] vp_list = list() vp_list.append(create_vp(self.model, 'MID_GAUSS', use_local=True)) vp_coeffs = numpy.ones([self.nants, len(key_nolls)+1]) for inoll, noll in enumerate(key_nolls): zernike = {'coeff': 1.0, 'noll': noll} vp_coeffs[:, inoll+1] = numpy.random.normal(0.0, 0.03, self.nants) vp_list.append(create_vp_generic_numeric(self.model, pointingcentre=None, diameter=15.0, blockage=0.0, taper='gaussian', edge=0.03162278, zernikes=[zernike], padding=2, use_local=True)) gt = simulate_gaintable_from_zernikes(self.vis, component, vp_list, vp_coeffs) import matplotlib.pyplot as plt assert gt[0].gain.shape == (self.ntimes, self.nants, 1, 1, 1), gt[0].gain.shape plt.clf() for ant in range(self.nants): plt.plot(gt[0].time, 1.0 / numpy.real(gt[0].gain[:, ant, 0, 0, 0]), '.') plt.xlabel('Time (s)') plt.ylabel('Gain') plt.show(block=False)
def test_simulate_gaintable_from_time_series(self): numpy.random.seed(18051955) offset_phasecentre = SkyCoord(ra=+15.0 * u.deg, dec=-44.58 * u.deg, frame='icrs', equinox='J2000') component = [ Skycomponent(frequency=self.frequency, direction=offset_phasecentre, polarisation_frame=PolarisationFrame("stokesI"), flux=[[1.0]]) ] for type in ['wind']: pt = create_pointingtable_from_blockvisibility(self.vis) import matplotlib.pyplot as plt ant = 15 plt.clf() plt.plot(pt.time, pt.nominal[:, ant, 0, 0, 0], '.') plt.plot(pt.time, pt.nominal[:, ant, 0, 0, 1], '.') plt.xlabel('Time (s)') plt.ylabel('Nominal (rad)') plt.title("Nominal pointing for %s" % (type)) plt.show() for reference_pointing in [False, True]: pt = simulate_pointingtable_from_timeseries( pt, type=type, reference_pointing=reference_pointing) import matplotlib.pyplot as plt ant = 15 plt.clf() r2a = 180.0 * 3600.0 / numpy.pi plt.plot(pt.time, r2a * pt.pointing[:, ant, 0, 0, 0], '.') plt.plot(pt.time, r2a * pt.pointing[:, ant, 0, 0, 1], '.') plt.xlabel('Time (s)') plt.ylabel('Pointing (arcsec)') plt.title("Pointing for %s, reference pointing %s" % (type, reference_pointing)) plt.show() vp = create_vp(self.model, 'MID') gt = simulate_gaintable_from_pointingtable( self.vis, component, pt, vp) assert gt[0].gain.shape == (self.ntimes, self.nants, 1, 1, 1), gt[0].gain.shape plt.clf() plt.plot(gt[0].time, 1.0 / numpy.real(gt[0].gain[:, ant, 0, 0, 0]), '.') plt.xlabel('Time (s)') plt.ylabel('Gain') plt.title("Gain for %s, reference pointing %s" % (type, reference_pointing)) plt.show()
def apply_beam_to_skycomponent(sc: Union[Skycomponent, List[Skycomponent]], beam: Image) \ -> Union[Skycomponent, List[Skycomponent]]: """ Insert a Skycomponent into an image :param beam: :param sc: SkyComponent or list of SkyComponents :return: List of skycomponents """ assert isinstance(beam, Image) single = not isinstance(sc, collections.Iterable) if single: sc = [sc] nchan, npol, ny, nx = beam.shape log.debug('apply_beam_to_skycomponent: Processing %d components' % (len(sc))) ras = [comp.direction.ra.radian for comp in sc] decs = [comp.direction.dec.radian for comp in sc] skycoords = SkyCoord(ras * u.rad, decs * u.rad, frame='icrs') pixlocs = skycoord_to_pixel(skycoords, beam.wcs, origin=1, mode='wcs') newsc = [] total_flux = numpy.zeros([nchan, npol]) for icomp, comp in enumerate(sc): assert comp.shape == 'Point', "Cannot handle shape %s" % comp.shape assert_same_chan_pol(beam, comp) pixloc = (pixlocs[0][icomp], pixlocs[1][icomp]) if not numpy.isnan(pixloc).any(): x, y = int(round(float(pixloc[0]))), int(round(float(pixloc[1]))) if 0 <= x < nx and 0 <= y < ny: comp.flux[:, :] *= beam.data[:, :, y, x] total_flux += comp.flux newsc.append( Skycomponent(comp.direction, comp.frequency, comp.name, comp.flux, shape=comp.shape, polarisation_frame=comp.polarisation_frame)) log.debug('apply_beam_to_skycomponent: %d components with total flux %s' % (len(newsc), total_flux)) if single: return newsc[0] else: return newsc
def actualSetup(self, sky_pol_frame='stokesIQUV', data_pol_frame='linear', f=None, vnchan=1): 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) if vnchan > 1: self.channel_bandwidth = numpy.array( vnchan * [self.frequency[1] - self.frequency[0]]) else: self.channel_bandwidth = numpy.array([2e7]) 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 = dft_skycomponent_visibility(self.vis, self.comp)
def create_skycomponent(direction: SkyCoord, flux: numpy.array, frequency: numpy.array, shape: str = 'Point', polarisation_frame=PolarisationFrame("stokesIQUV"), params: dict = None, name: str = '') \ -> Skycomponent: """ A single Skycomponent with direction, flux, shape, and params for the shape :param polarisation_frame: :param params: :param direction: :param flux: :param frequency: :param shape: 'Point' or 'Gaussian' :param name: :return: Skycomponent """ return Skycomponent(direction=direction, frequency=frequency, name=name, flux=numpy.array(flux), shape=shape, params=params, polarisation_frame=polarisation_frame)
def convert_hdf_to_skycomponent(f): """ Convert HDF root to a SkyComponent :param f: :return: """ assert f.attrs['RASCIL_data_model'] == "Skycomponent", "Not a Skycomponent" direction = convert_direction_from_string(f.attrs['direction']) frequency = numpy.array(f.attrs['frequency']) name = f.attrs['name'] polarisation_frame = PolarisationFrame(f.attrs['polarisation_frame']) flux = f.attrs['flux'] shape = f.attrs['shape'] params = ast.literal_eval(f.attrs['params']) sc = Skycomponent(direction=direction, frequency=frequency, name=name, flux=flux, polarisation_frame=polarisation_frame, shape=shape, params=params) return sc
def actualSetup(self, sky_pol_frame='stokesIQUV', data_pol_frame='linear'): self.lowcore = create_named_configuration('LOWBD2', rmax=100.0) self.times = (numpy.pi / 43200.0) * numpy.arange(0.0, 3000.0, 60.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 = dft_skycomponent_visibility(self.vis, self.comp)
def apply_voltage_pattern_to_skycomponent(sc: Union[Skycomponent, List[Skycomponent]], vp: Image, inverse=False) \ -> Union[Skycomponent, List[Skycomponent]]: """ Apply a voltage pattern to a Skycomponent For inverse==False, input polarisation_frame must be stokesIQUV, and output polarisation_frame is same as voltage pattern For inverse==True, input polarisation_frame must be same as voltage pattern, and output polarisation_frame is "stokesIQUV" Requires a complex Image with the correct ordering of polarisation axes: e.g. RR, LL, RL, LR or XX, YY, XY, YX :param vp: voltage pattern as complex image :param sc: SkyComponent or list of SkyComponents :return: List of skycomponents """ assert isinstance(vp, Image) assert (vp.polarisation_frame == PolarisationFrame("linear")) or \ (vp.polarisation_frame == PolarisationFrame("circular")) assert vp.data.dtype == "complex128" single = not isinstance(sc, collections.abc.Iterable) if single: sc = [sc] nchan, npol, ny, nx = vp.shape log.debug('apply_vp_to_skycomponent: Processing %d components' % (len(sc))) ras = [comp.direction.ra.radian for comp in sc] decs = [comp.direction.dec.radian for comp in sc] skycoords = SkyCoord(ras * u.rad, decs * u.rad, frame='icrs') pixlocs = skycoord_to_pixel(skycoords, vp.wcs, origin=1, mode='wcs') newsc = [] total_flux = numpy.zeros([nchan, npol], dtype="complex") for icomp, comp in enumerate(sc): assert comp.shape == 'Point', "Cannot handle shape %s" % comp.shape assert_same_chan_pol(vp, comp) # Convert to linear (xx, xy, yx, yy) or circular (rr, rl, lr, ll) nchan, npol = comp.flux.shape assert npol == 4 if not inverse: assert comp.polarisation_frame == PolarisationFrame("stokesIQUV") comp_flux_cstokes = \ convert_pol_frame(comp.flux, comp.polarisation_frame, vp.polarisation_frame).reshape([nchan, 2, 2]) comp_flux = numpy.zeros([nchan, npol], dtype='complex') pixloc = (pixlocs[0][icomp], pixlocs[1][icomp]) if not numpy.isnan(pixloc).any(): x, y = int(round(float(pixloc[0]))), int(round(float(pixloc[1]))) if 0 <= x < nx and 0 <= y < ny: # Now we want to left and right multiply by the Jones matrices # comp_flux = vp.data[:, :, y, x] * comp_flux_cstokes * numpy.vp.data[:, :, y, x] for chan in range(nchan): ej = vp.data[chan, :, y, x].reshape([2, 2]) cfs = comp_flux_cstokes[chan].reshape([2, 2]) comp_flux[chan, :] = apply_jones(ej, cfs, inverse).reshape([4]) total_flux += comp_flux if inverse: comp_flux = convert_pol_frame( comp_flux, vp.polarisation_frame, PolarisationFrame("stokesIQUV")) comp.polarisation_frame = PolarisationFrame("stokesIQUV") newsc.append( Skycomponent(comp.direction, comp.frequency, comp.name, comp_flux, shape=comp.shape, polarisation_frame=vp.polarisation_frame)) log.debug('apply_vp_to_skycomponent: %d components with total flux %s' % (len(newsc), total_flux)) if single: return newsc[0] else: return newsc
def create_simulation_components(context, phasecentre, frequency, pbtype, offset_dir, flux_limit, pbradius, pb_npixel, pb_cellsize, show=False): """ Construct components for simulation :param context: :param phasecentre: :param frequency: :param pbtype: :param offset_dir: :param flux_limit: :param pbradius: :param pb_npixel: :param pb_cellsize: :return: """ HWHM_deg, null_az_deg, null_el_deg = find_pb_width_null(pbtype, frequency) dec = phasecentre.dec.deg ra = phasecentre.ra.deg if context == 'singlesource': log.info("create_simulation_components: Constructing single component") offset = [HWHM_deg * offset_dir[0], HWHM_deg * offset_dir[1]] log.info( "create_simulation_components: Offset from pointing centre = %.3f, %.3f deg" % (offset[0], offset[1])) # The point source is offset to approximately the halfpower point offset_direction = SkyCoord( ra=(ra + offset[0] / numpy.cos(numpy.pi * dec / 180.0)) * units.deg, dec=(dec + offset[1]) * units.deg, frame='icrs', equinox='J2000') original_components = [ Skycomponent(flux=[[1.0]], direction=offset_direction, frequency=frequency, polarisation_frame=PolarisationFrame('stokesI')) ] elif context == 'null': log.info( "create_simulation_components: Constructing single component at the null" ) offset = [null_az_deg * offset_dir[0], null_el_deg * offset_dir[1]] HWHM = HWHM_deg * numpy.pi / 180.0 log.info( "create_simulation_components: Offset from pointing centre = %.3f, %.3f deg" % (offset[0], offset[1])) # The point source is offset to approximately the null point offset_direction = SkyCoord( ra=(ra + offset[0] / numpy.cos(numpy.pi * dec / 180.0)) * units.deg, dec=(dec + offset[1]) * units.deg, frame='icrs', equinox='J2000') original_components = [ Skycomponent(flux=[[1.0]], direction=offset_direction, frequency=frequency, polarisation_frame=PolarisationFrame('stokesI')) ] else: offset = [0.0, 0.0] # Make a skymodel from S3 max_flux = 0.0 total_flux = 0.0 log.info("create_simulation_components: Constructing s3sky components") from rascil.processing_components.simulation import create_test_skycomponents_from_s3 original_components = create_test_skycomponents_from_s3( flux_limit=flux_limit / 100.0, phasecentre=phasecentre, polarisation_frame=PolarisationFrame("stokesI"), frequency=numpy.array(frequency), radius=pbradius) log.info( "create_simulation_components: %d components before application of primary beam" % (len(original_components))) pbmodel = create_image(npixel=pb_npixel, cellsize=pb_cellsize, phasecentre=phasecentre, frequency=frequency, polarisation_frame=PolarisationFrame("stokesI")) pb = create_pb(pbmodel, "MID_GAUSS", pointingcentre=phasecentre, use_local=False) pb_feko = create_pb(pbmodel, pbtype, pointingcentre=phasecentre, use_local=True) pb.data = pb_feko.data[:, 0, ...][:, numpy.newaxis, ...] pb_applied_components = [ copy_skycomponent(c) for c in original_components ] pb_applied_components = apply_beam_to_skycomponent( pb_applied_components, pb) filtered_components = [] for icomp, comp in enumerate(pb_applied_components): if comp.flux[0, 0] > flux_limit: total_flux += comp.flux[0, 0] if abs(comp.flux[0, 0]) > max_flux: max_flux = abs(comp.flux[0, 0]) filtered_components.append(original_components[icomp]) log.info( "create_simulation_components: %d components > %.3f Jy after application of primary beam" % (len(filtered_components), flux_limit)) log.info( "create_simulation_components: Strongest components is %g (Jy)" % max_flux) log.info( "create_simulation_components: Total flux in components is %g (Jy)" % total_flux) original_components = [ copy_skycomponent(c) for c in filtered_components ] if show: plt.clf() show_image(pb, components=original_components) plt.show(block=False) log.info("create_simulation_components: Created %d components" % len(original_components)) # Primary beam points to the phasecentre offset_direction = SkyCoord(ra=ra * units.deg, dec=dec * units.deg, frame='icrs', equinox='J2000') return original_components, offset_direction
def find_skycomponents(im: Image, fwhm=1.0, threshold=1.0, npixels=5) -> List[Skycomponent]: """ Find gaussian components in Image above a certain threshold as Skycomponent :param im: Image to be searched :param fwhm: Full width half maximum of gaussian in pixels :param threshold: Threshold for component detection. Default: 1 Jy. :param npixels: Number of connected pixels required :return: list of sky components """ assert isinstance(im, Image) log.info("find_skycomponents: Finding components in Image by segmentation") # We use photutils segmentation - this first segments the image # into pieces that are thought to contain individual sources, then # identifies the concrete source properties. Having these two # steps makes it straightforward to extract polarisation and # spectral information. # Make filter kernel sigma = fwhm * gaussian_fwhm_to_sigma kernel = Gaussian2DKernel(sigma, x_size=int(1.5 * fwhm), y_size=int(1.5 * fwhm)) kernel.normalize() # Segment the average over all channels of Stokes I image_sum = numpy.sum(im.data, axis=0)[0, ...] / float(im.shape[0]) segments = segmentation.detect_sources(image_sum, threshold, npixels=npixels, filter_kernel=kernel) assert segments is not None, "Failed to find any components" log.info("find_skycomponents: Identified %d segments" % segments.nlabels) # Now compute source properties for all polarisations and frequencies comp_tbl = [[ segmentation.source_properties(im.data[chan, pol], segments, filter_kernel=kernel, wcs=im.wcs.sub([1, 2])).to_table() for pol in [0] ] for chan in range(im.nchan)] def comp_prop(comp, prop_name): return [[comp_tbl[chan][pol][comp][prop_name] for pol in [0]] for chan in range(im.nchan)] # Generate components comps = [] for segment in range(segments.nlabels): # Get flux and position. Astropy's quantities make this # unnecessarily complicated. flux = numpy.array(comp_prop(segment, "max_value")) # These values seem inconsistent with the xcentroid, and ycentroid values # ras = u.Quantity(list(map(u.Quantity, # comp_prop(segment, "ra_icrs_centroid")))) # decs = u.Quantity(list(map(u.Quantity, # comp_prop(segment, "dec_icrs_centroid")))) xs = u.Quantity(list(map(u.Quantity, comp_prop(segment, "xcentroid")))) ys = u.Quantity(list(map(u.Quantity, comp_prop(segment, "ycentroid")))) sc = pixel_to_skycoord(xs, ys, im.wcs, 0) ras = sc.ra decs = sc.dec # Remove NaNs from RA/DEC (happens if there is no flux in that # polarsiation/channel) # ras[numpy.isnan(ras)] = 0.0 # decs[numpy.isnan(decs)] = 0.0 # Determine "true" position by weighting flux_sum = numpy.sum(flux) ra = numpy.sum(flux * ras) / flux_sum dec = numpy.sum(flux * decs) / flux_sum xs = numpy.sum(flux * xs) / flux_sum ys = numpy.sum(flux * ys) / flux_sum point_flux = im.data[:, :, numpy.round(ys.value).astype('int'), numpy.round(xs.value).astype('int')] # Add component comps.append( Skycomponent(direction=SkyCoord(ra=ra, dec=dec), frequency=im.frequency, name="Segment %d" % segment, flux=point_flux, shape='Point', polarisation_frame=im.polarisation_frame, params={})) return comps
print("Constructing single component") offset = [HWHM_deg, 0.0] if opposite: offset = [-1.0 * offset[0], -1.0 * offset[1]] print("Offset from pointing centre = %.3f, %.3f deg" % (offset[0], offset[1])) # The point source is offset to approximately the halfpower point offset_direction = SkyCoord(ra=(+15.0 + offset[0]) * u.deg, dec=(declination + offset[1]) * u.deg, frame='icrs', equinox='J2000') original_components = [ Skycomponent(flux=[[1.0]], direction=offset_direction, frequency=frequency, polarisation_frame=PolarisationFrame('stokesI')) ] print(original_components[0]) else: # Make a skymodel from S3 max_flux = 0.0 total_flux = 0.0 print("Constructing s3sky components") from rascil.processing_components.simulation.testing_support import create_test_skycomponents_from_s3 original_components = create_test_skycomponents_from_s3( flux_limit=flux_limit / 100.0, phasecentre=phasecentre, polarisation_frame=PolarisationFrame("stokesI"),
def create_simulation_components( context, phasecentre, frequency, pbtype, offset_dir, flux_limit, pbradius, pb_npixel, pb_cellsize, show=False, fov=10, polarisation_frame=PolarisationFrame("stokesI"), filter_by_primary_beam=True, flux_max=10.0): """ Construct components for simulation :param context: singlesource or null or s3sky :param phasecentre: Centre of components :param frequency: Frequency :param pbtype: Type of primary beam :param offset_dir: Offset in ra, dec degrees :param flux_limit: Lower limit flux :param pbradius: Radius of components in radians :param pb_npixel: Number of pixels in the primary beam model :param pb_cellsize: Cellsize in primary beam model :param fov: FOV in degrees (used to select catalog) :param flux_max: Maximum flux in model before application of primary beam :param filter_by_primary_beam: Filter components by primary beam :param polarisation_frame: :param show: :return: """ HWHM_deg, null_az_deg, null_el_deg = find_pb_width_null(pbtype, frequency) dec = phasecentre.dec.deg ra = phasecentre.ra.deg if context == 'singlesource': log.info("create_simulation_components: Constructing single component") offset = [HWHM_deg * offset_dir[0], HWHM_deg * offset_dir[1]] log.info( "create_simulation_components: Offset from pointing centre = %.3f, %.3f deg" % (offset[0], offset[1])) # The point source is offset to approximately the halfpower point odirection = SkyCoord( ra=(ra + offset[0] / numpy.cos(numpy.pi * dec / 180.0)) * units.deg, dec=(dec + offset[1]) * units.deg, frame='icrs', equinox='J2000') if polarisation_frame.type == "stokesIQUV": original_components = [ Skycomponent( flux=[[1.0, 0.0, 0.0, 0.0]], direction=odirection, frequency=frequency, polarisation_frame=PolarisationFrame('stokesIQUV')) ] else: original_components = [ Skycomponent(flux=[[1.0]], direction=odirection, frequency=frequency, polarisation_frame=PolarisationFrame('stokesI')) ] offset_direction = odirection elif context == 'doublesource': original_components = [] log.info( "create_simulation_components: Constructing double components") for sign_offset in [(-1, 0), (1, 0)]: offset = [HWHM_deg * sign_offset[0], HWHM_deg * sign_offset[1]] log.info( "create_simulation_components: Offset from pointing centre = %.3f, %.3f deg" % (offset[0], offset[1])) odirection = SkyCoord( ra=(ra + offset[0] / numpy.cos(numpy.pi * dec / 180.0)) * units.deg, dec=(dec + offset[1]) * units.deg, frame='icrs', equinox='J2000') if polarisation_frame.type == "stokesIQUV": original_components.append( Skycomponent( flux=[[1.0, 0.0, 0.0, 0.0]], direction=odirection, frequency=frequency, polarisation_frame=PolarisationFrame('stokesIQUV'))) else: original_components.append( Skycomponent( flux=[[1.0]], direction=odirection, frequency=frequency, polarisation_frame=PolarisationFrame('stokesI'))) for o in original_components: print(o) offset_direction = odirection elif context == 'null': log.info( "create_simulation_components: Constructing single component at the null" ) offset = [null_az_deg * offset_dir[0], null_el_deg * offset_dir[1]] HWHM = HWHM_deg * numpy.pi / 180.0 log.info( "create_simulation_components: Offset from pointing centre = %.3f, %.3f deg" % (offset[0], offset[1])) # The point source is offset to approximately the null point offset_direction = SkyCoord( ra=(ra + offset[0] / numpy.cos(numpy.pi * dec / 180.0)) * units.deg, dec=(dec + offset[1]) * units.deg, frame='icrs', equinox='J2000') if polarisation_frame.type == "stokesIQUV": original_components = [ Skycomponent( flux=[[1.0, 0.0, 0.0, 0.0]], direction=offset_direction, frequency=frequency, polarisation_frame=PolarisationFrame('stokesIQUV')) ] else: original_components = [ Skycomponent(flux=[[1.0]], direction=offset_direction, frequency=frequency, polarisation_frame=PolarisationFrame('stokesI')) ] else: offset = [0.0, 0.0] # Make a skymodel from S3 max_flux = 0.0 total_flux = 0.0 log.info("create_simulation_components: Constructing s3sky components") from rascil.processing_components.simulation import create_test_skycomponents_from_s3 all_components = create_test_skycomponents_from_s3( flux_limit=flux_limit / 100.0, phasecentre=phasecentre, polarisation_frame=polarisation_frame, frequency=numpy.array(frequency), radius=pbradius, fov=fov) original_components = filter_skycomponents_by_flux(all_components, flux_max=flux_max) log.info( "create_simulation_components: %d components before application of primary beam" % (len(original_components))) if filter_by_primary_beam: pbmodel = create_image( npixel=pb_npixel, cellsize=pb_cellsize, phasecentre=phasecentre, frequency=frequency, polarisation_frame=PolarisationFrame("stokesI")) stokesi_components = [ copy_skycomponent(o) for o in original_components ] for s in stokesi_components: s.flux = numpy.array([[s.flux[0, 0]]]) s.polarisation_frame = PolarisationFrame("stokesI") pb = create_pb(pbmodel, "MID_GAUSS", pointingcentre=phasecentre, use_local=False) pb_applied_components = [ copy_skycomponent(c) for c in stokesi_components ] pb_applied_components = apply_beam_to_skycomponent( pb_applied_components, pb) filtered_components = [] for icomp, comp in enumerate(pb_applied_components): if comp.flux[0, 0] > flux_limit: total_flux += comp.flux[0, 0] if abs(comp.flux[0, 0]) > max_flux: max_flux = abs(comp.flux[0, 0]) filtered_components.append(original_components[icomp]) log.info( "create_simulation_components: %d components > %.3f Jy after filtering with primary beam" % (len(filtered_components), flux_limit)) log.info( "create_simulation_components: Strongest components is %g (Jy)" % max_flux) log.info( "create_simulation_components: Total flux in components is %g (Jy)" % total_flux) original_components = [ copy_skycomponent(c) for c in filtered_components ] if show: plt.clf() show_image(pb, components=original_components) plt.show(block=False) log.info("create_simulation_components: Created %d components" % len(original_components)) # Primary beam points to the phasecentre offset_direction = SkyCoord(ra=ra * units.deg, dec=dec * units.deg, frame='icrs', equinox='J2000') return original_components, offset_direction
def create_low_test_skycomponents_from_gleam(flux_limit=0.1, polarisation_frame=PolarisationFrame("stokesI"), frequency=numpy.array([1e8]), kind='cubic', phasecentre=None, radius=1.0) \ -> List[Skycomponent]: """Create sky components from the GLEAM survey Stokes I is estimated from a cubic spline fit to the measured fluxes. The polarised flux is always zero. See http://www.mwatelescope.org/science/gleam-survey The catalog is available from Vizier. VIII/100 GaLactic and Extragalactic All-sky MWA survey (Hurley-Walker+, 2016) GaLactic and Extragalactic All-sky Murchison Wide Field Array (GLEAM) survey. I: A low-frequency extragalactic catalogue. Hurley-Walker N., et al., Mon. Not. R. Astron. Soc., 464, 1146-1167 (2017), 2017MNRAS.464.1146H :param flux_limit: Only write components brighter than this (Jy) :param polarisation_frame: Polarisation frame (default PolarisationFrame("stokesI")) :param frequency: Frequencies at which the flux will be estimated :param kind: Kind of interpolation (see scipy.interpolate.interp1d) Default: linear :param phasecentre: Desired phase centre (SkyCoord) default None implies all sources :param radius: Radius of sources selected around phasecentre (default 1.0 rad) :return: List of Skycomponents """ check_data_directory() fitsfile = rascil_path("data/models/GLEAM_EGC.fits") rad2deg = 180.0 / numpy.pi decmin = phasecentre.dec.to('deg').value - rad2deg * radius / 2.0 decmax = phasecentre.dec.to('deg').value + rad2deg * radius / 2.0 hdulist = fits.open(fitsfile, lazy_load_hdus=False) recs = hdulist[1].data[0].array fluxes = recs['peak_flux_wide'] mask = fluxes > flux_limit filtered_recs = recs[mask] decs = filtered_recs['DEJ2000'] mask = decs > decmin filtered_recs = filtered_recs[mask] decs = filtered_recs['DEJ2000'] mask = decs < decmax filtered_recs = filtered_recs[mask] ras = filtered_recs['RAJ2000'] decs = filtered_recs['DEJ2000'] names = filtered_recs['Name'] if polarisation_frame is None: polarisation_frame = PolarisationFrame("stokesI") npol = polarisation_frame.npol nchan = len(frequency) # For every source, we read all measured fluxes and interpolate to the # required frequencies gleam_freqs = numpy.array([ 76, 84, 92, 99, 107, 115, 122, 130, 143, 151, 158, 166, 174, 181, 189, 197, 204, 212, 220, 227 ]) gleam_flux_freq = numpy.zeros([len(names), len(gleam_freqs)]) for i, f in enumerate(gleam_freqs): gleam_flux_freq[:, i] = filtered_recs['int_flux_%03d' % (f)][:] skycomps = [] directions = SkyCoord(ra=ras * u.deg, dec=decs * u.deg) if phasecentre is not None: separations = directions.separation(phasecentre).to('rad').value else: separations = numpy.zeros(len(names)) for isource, name in enumerate(names): direction = directions[isource] if separations[isource] < radius: fint = interpolate.interp1d(gleam_freqs * 1.0e6, gleam_flux_freq[isource, :], kind=kind) flux = numpy.zeros([nchan, npol]) flux[:, 0] = fint(frequency) if not numpy.isnan(flux).any(): skycomps.append( Skycomponent(direction=direction, flux=flux, frequency=frequency, name=name, shape='Point', polarisation_frame=polarisation_frame)) log.info( 'create_low_test_skycomponents_from_gleam: %d sources above flux limit %.3f' % (len(skycomps), flux_limit)) hdulist.close() return skycomps
def create_test_skycomponents_from_s3(polarisation_frame=PolarisationFrame( "stokesI"), frequency=numpy.array([1e8]), channel_bandwidth=numpy.array([1e6]), phasecentre=None, fov=20, flux_limit=1e-3, radius=None): """Create test image from S3 The input catalog was generated at http://s-cubed.physics.ox.ac.uk/s3_sex using the following query:: Database: s3_sex SQL: select * from Galaxies where (pow(10,itot_151)*1000 > 1.0) and (right_ascension between -5 and 5) and (declination between -5 and 5);; Number of rows returned: 29966 For frequencies < 610MHz, there are three tables to use:: data/models/S3_151MHz_10deg.csv, use fov=10 data/models/S3_151MHz_20deg.csv, use fov=20 data/models/S3_151MHz_40deg.csv, use fov=40 For frequencies > 610MHz, there are three tables: data/models/S3_1400MHz_1mJy_10deg.csv, use flux_limit>= 1e-3 data/models/S3_1400MHz_100uJy_10deg.csv, use flux_limit < 1e-3 data/models/S3_1400MHz_1mJy_18deg.csv, use flux_limit>= 1e-3 data/models/S3_1400MHz_100uJy_18deg.csv, use flux_limit < 1e-3 The component spectral index is calculated from the 610MHz and 151MHz or 1400MHz and 610MHz, and then calculated for the specified frequencies. If polarisation_frame is not stokesI then the image will a polarised axis but the values will be zero. :param polarisation_frame: Polarisation frame (default PolarisationFrame("stokesI")) :param frequency: :param channel_bandwidth: Channel width (Hz) :param phasecentre: phasecentre (SkyCoord) :param fov: fov 10 | 20 | 40 :param flux_limit: Minimum flux (Jy) :return: Image """ check_data_directory() ras = [] decs = [] fluxes = [] names = [] if phasecentre is None: phasecentre = SkyCoord(ra=+180.0 * u.deg, dec=-60.0 * u.deg, frame='icrs', equinox='J2000') if polarisation_frame is None: polarisation_frame = PolarisationFrame("stokesI") if numpy.max(frequency) > 6.1E8: if fov > 10: fovstr = '18' else: fovstr = '10' if flux_limit >= 1e-3: csvfilename = rascil_data_path('models/S3_1400MHz_1mJy_%sdeg.csv' % fovstr) else: csvfilename = rascil_data_path( 'models/S3_1400MHz_100uJy_%sdeg.csv' % fovstr) log.info( 'create_test_skycomponents_from_s3: Reading S3-SEX sources from %s ' % csvfilename) else: assert fov in [ 10, 20, 40 ], "Field of view invalid: use one of %s" % ([10, 20, 40]) csvfilename = rascil_data_path('models/S3_151MHz_%ddeg.csv' % (fov)) log.info( 'create_test_skycomponents_from_s3: Reading S3-SEX sources from %s ' % csvfilename) skycomps = list() with open(csvfilename) as csvfile: readCSV = csv.reader(csvfile, delimiter=',') r = 0 for row in readCSV: # Skip first row if r > 0: ra = float(row[4]) / numpy.cos( phasecentre.dec.rad) + phasecentre.ra.deg dec = float(row[5]) + phasecentre.dec.deg if numpy.max(frequency) > 6.1E8: alpha = (float(row[11]) - float(row[10])) / numpy.log10( 1400.0 / 610.0) flux = numpy.power(10, float(row[10])) * numpy.power( frequency / 1.4e9, alpha) else: alpha = (float(row[10]) - float(row[9])) / numpy.log10( 610.0 / 151.0) flux = numpy.power(10, float(row[9])) * numpy.power( frequency / 1.51e8, alpha) if numpy.max(flux) > flux_limit: ras.append(ra) decs.append(dec) if polarisation_frame == PolarisationFrame("stokesIQUV"): polscale = numpy.array([1.0, 0.0, 0.0, 0.0]) fluxes.append(numpy.outer(flux, polscale)) else: fluxes.append([[f] for f in flux]) names.append("S3_%s" % row[0]) r += 1 csvfile.close() assert len(fluxes) > 0, "No sources found above flux limit %s" % flux_limit directions = SkyCoord(ra=ras * u.deg, dec=decs * u.deg) if phasecentre is not None: separations = directions.separation(phasecentre).to('rad').value else: separations = numpy.zeros(len(names)) for isource, name in enumerate(names): direction = directions[isource] if separations[isource] < radius: if not numpy.isnan(flux).any(): skycomps.append( Skycomponent(direction=direction, flux=fluxes[isource], frequency=frequency, name=names[isource], shape='Point', polarisation_frame=polarisation_frame)) log.info( 'create_test_skycomponents_from_s3: %d sources found above fluxlimit inside search radius' % len(skycomps)) return skycomps