def deconvolve_moments(moments, beam, pa, pixscale): if moments['rmsx_ex'] >= moments['rmsy_ex']: beam_ex = Beam(major=moments['rmsx_ex'] * pixscale * sig2fwhm, minor=moments['rmsy_ex'] * pixscale * sig2fwhm, pa=pa * u.rad) else: beam_ex = Beam(major=moments['rmsy_ex'] * pixscale * sig2fwhm, minor=moments['rmsx_ex'] * pixscale * sig2fwhm, pa=(pa + np.pi / 2) * u.rad) beam_ex_dc = beam_ex.deconvolve(beam, failure_returns_pointlike=True) if moments['rmsx_noex'] >= moments['rmsy_noex']: beam_noex = Beam(major=moments['rmsx_noex'] * pixscale * sig2fwhm, minor=moments['rmsy_noex'] * pixscale * sig2fwhm, pa=pa * u.rad) else: beam_noex = Beam(major=moments['rmsy_noex'] * pixscale * sig2fwhm, minor=moments['rmsx_noex'] * pixscale * sig2fwhm, pa=(pa + np.pi / 2) * u.rad) beam_noex_dc = beam_noex.deconvolve(beam, failure_returns_pointlike=True) outdict = {} outdict['rmsx_ex'] = (beam_ex_dc.major / pixscale / sig2fwhm).to( u.dimensionless_unscaled).value outdict['rmsy_ex'] = (beam_ex_dc.minor / pixscale / sig2fwhm).to( u.dimensionless_unscaled).value outdict['pa_ex'] = (beam_ex_dc.pa).to(u.rad).value outdict['rmsx_noex'] = (beam_noex.major / pixscale / sig2fwhm).to( u.dimensionless_unscaled).value outdict['rmsy_noex'] = (beam_noex.minor / pixscale / sig2fwhm).to( u.dimensionless_unscaled).value outdict['pa_noex'] = (beam_noex.pa).to(u.rad).value return (outdict)
def main(args): hdul = fits.open(args.file_in, 'readonly') raw_img = np.squeeze(hdul[0].data) img_wcs = wcs.WCS(hdul[0].header) pixscale = wcs.utils.proj_plane_pixel_area(img_wcs.celestial)**0.5 * u.deg raw_beam = Beam(args.beam * u.arcmin) new_beam = Beam(args.cbeam * u.arcmin) cov_beam = new_beam.deconvolve(raw_beam) cov_kernel = cov_beam.as_kernel(pixscale) new_img = convolution.convolve_fft(raw_img, cov_kernel, normalize_kernel=True, allow_huge=True) print(new_img.shape) new_data = np.reshape(new_img, hdul[0].data.shape) print(new_data.shape) new_hdu = fits.PrimaryHDU(new_data) new_hdu.header = hdul[0].header.copy() new_hdu.header['NAXIS'] = 4 new_hdu.writeto(args.fileout, overwrite=True) return 0
def image_sz512as_pl1p5_fwhm2as_scale1as(tmp_path): pixel_scale = 1 * units.arcsec restfreq = 100 * units.GHz highres_major = 2 * units.arcsec # Generate input image input_hdu = generate_test_fits(imsize=512, powerlaw=1.5, beamfwhm=highres_major, pixel_scale=pixel_scale, restfreq=restfreq, brightness_unit=units.Jy / units.sr) input_fn = tmp_path / "input_image_sz512as_pl1.5_fwhm2as_scale1as.fits" input_hdu.writeto(input_fn, overwrite=True) input_proj = Projection.from_hdu(input_hdu).to(units.Jy / units.beam) # Make Interferometric image intf_data = interferometrically_observe_image(image=input_hdu.data, pixel_scale=pixel_scale, largest_angular_scale=40*units.arcsec, smallest_angular_scale=highres_major)[0].real intf_hdu = fits.PrimaryHDU(data=intf_data.value if hasattr(intf_data, "value") else intf_data, header=input_hdu.header) intf_proj = Projection.from_hdu(intf_hdu).to(units.Jy / units.beam) intf_fn = tmp_path / "input_image_sz512as_pl1.5_fwhm2as_scale1as_intf2to40as.fits" intf_proj.write(intf_fn, overwrite=True) # Make SD image sd_header = input_hdu.header.copy() major = 15*units.arcsec # Eff SD diam (to compare with CASA in troubleshooting) sd_beam = Beam(major=major) sd_header.update(sd_beam.to_header_keywords()) sd_fn = tmp_path / "input_image_sz512as_pl1.5_fwhm2as_scale1as_sd15as.fits" sd_data = singledish_observe_image(input_hdu.data, pixel_scale=pixel_scale, beam=sd_beam, boundary='wrap') sd_hdu = fits.PrimaryHDU(data=sd_data.value if hasattr(sd_data, "value") else sd_data, header=sd_header) sd_hdu.header.update(sd_beam.to_header_keywords()) sd_proj = Projection.from_hdu(sd_hdu).to(units.Jy / units.beam) sd_proj.write(sd_fn, overwrite=True) return tmp_path, input_fn, intf_fn, sd_fn
def fixJialu(image, beam=15.0): ''' Purpose: fix up Jialu's IC0342 cube so we can use it for analysis for DEGAS ''' #12CO rest frequency rest_freq_12co = 115.27120180 * u.GHz f = fits.open(image) f[0].header['BUNIT'] = 'K' f[0].header['RESTFRQ'] = float(rest_freq_12co.to(u.Hz).value) f.writeto(image.replace('.fits', '_fixed.fits'), overwrite=True) image = image.replace('.fits', '_fixed.fits') # open image cube = SpectralCube.read(image) cube_kms = cube.with_spectral_unit(u.km / u.s) ## This should set header #cube_ms = cube.with_spectral_unit(u.m / u.s, rest_value=rest_freq_12co) # chop off bad edge subcube = cube_kms.subcube(xlo=0, xhi=134, ylo=0, yhi=150) # add beam beamcube = subcube.with_beam(Beam(8.0 * u.arcsec)) # smooth newBeam = Beam(beam * u.arcsec) smoothCube = beamcube.convolve_to(newBeam) # smooth spectrally. smoothFactor = 3.0 spSmoothCube = smoothCube.spectral_smooth(Box1DKernel(smoothFactor)) spec_axis = spSmoothCube.spectral_axis chan_width = spec_axis[1] - spec_axis[ 0] # channels are equally spaced in velocity new_axis = np.arange(spec_axis[0].value, spec_axis[-1].value, smoothFactor * chan_width.value) * u.km / u.s interpCube = spSmoothCube.spectral_interpolate( new_axis, suppress_smooth_warning=False) # write out interpCube.write(image.replace('8arcsec_fixed.fits', '10kms_gauss15.fits'), overwrite=True)
def test_projection_attach_beam(): exp_beam = Beam(1.0 * u.arcsec) newbeam = Beam(2.0 * u.arcsec) proj, hdu = load_projection("55.fits") new_proj = proj.with_beam(newbeam) assert proj.beam == exp_beam assert proj.meta['beam'] == exp_beam assert new_proj.beam == newbeam assert new_proj.meta['beam'] == newbeam
def test_projection_from_hdu_with_beam(LDO, data): p = LDO(data, copy=False) hdu = p.hdu beam = Beam(1 * u.arcsec) hdu.header = beam.attach_to_header(hdu.header) p_new = LDO.from_hdu(hdu) assert (p == p_new).all() assert beam == p_new.meta['beam'] assert beam == p_new.beam
def test_ldo_attach_beam(LDO, data): exp_beam = Beam(1.0 * u.arcsec) newbeam = Beam(2.0 * u.arcsec) p = LDO(data, copy=False, beam=exp_beam) new_p = p.with_beam(newbeam) assert p.beam == exp_beam assert p.meta['beam'] == exp_beam assert new_p.beam == newbeam assert new_p.meta['beam'] == newbeam
def jy_beam_MJy_sr(data, header): """Funtion which converts fits data into units of Jy/sr""" if header['BUNIT'] == 'Jy/beam': beam = Beam.from_fits_header(header) SB = ((data * u.Jy / u.beam).to( u.MJy / u.sr, equivalencies=u.beam_angular_area(beam))).value elif header['BUNIT'] == 'JY/BEAM': beam = Beam.from_fits_header(header) SB = ((data * u.Jy / u.beam).to( u.MJy / u.sr, equivalencies=u.beam_angular_area(beam))).value elif header['BUNIT'] == 'MJy/sr': SB = data return SB
def fits_reconvolve_psf(fitsfile, newpsf, out=None): """ Convolve image with deconvolution of (newpsf, oldpsf) """ newparams = newpsf.to_header_keywords() if out is None: logging.debug('fits_reconvolve: Overwriting file %s', fitsfile) out = fitsfile with fits.open(fitsfile) as hdul: hdr = hdul[0].header currentpsf = Beam.from_fits_header(hdr) if currentpsf != newpsf: kmaj1 = (currentpsf.major.to('deg').value/hdr['CDELT2']) kmin1 = (currentpsf.minor.to('deg').value/hdr['CDELT2']) kpa1 = currentpsf.pa.to('deg').value kmaj2 = (newpsf.major.to('deg').value/hdr['CDELT2']) kmin2 = (newpsf.minor.to('deg').value/hdr['CDELT2']) kpa2 = newpsf.pa.to('deg').value norm = newpsf.to_value() / currentpsf.to_value() if len(hdul[0].data.shape) == 4: conv_data = hdul[0].data[0,0,...] elif len(hdul[0].data.shape) == 2: conv_data = hdul[0].data # deconvolve with the old PSF # conv_data = convolve_gaussian_kernel(conv_data, kmaj1, kmin1, kpa1, inverse=True) # convolve to the new PSF conv_data = norm * reconvolve_gaussian_kernel(conv_data, kmaj1, kmin1, kpa1, kmaj2, kmin2, kpa2) if len(hdul[0].data.shape) == 4: hdul[0].data[0,0,...] = conv_data elif len(hdul[0].data.shape) == 2: hdul[0].data = conv_data hdr = newpsf.attach_to_header(hdr) fits.writeto(out, data=hdul[0].data, header=hdr, overwrite=True) return out
def get_spatialsmooth(cube, res_t): """Spatailly smooth data Parameters ---------- cube : spectral cube object res_t : float target *resolusion* (in arcsec) *not* channel width - do get_spectralregrid Returns ------- smcube = Output cube containing the spatailly smoothed data and updated header """ res_c = cube.header['BMAJ'] * 3600 print("[INFO] Current resolution of %0.1f arcsec" % (res_c)) print("[INFO] Target resolution of %0.1f arcsec" % (res_t)) res_t_ = Beam(major=res_t * au.arcsec, minor=res_t * au.arcsec, pa=0 * au.deg) smcube = cube.convolve_to(res_t_) return smcube
def test_preserve_beam(): cube, data = cube_and_raw('advs.fits') beam = Beam.from_fits_header(path("advs.fits")) assert cube.beam == beam
def getimdata(cubenm, verbose=False): """Get fits image data """ if verbose: print(f'Getting image data from {cubenm}') with fits.open(cubenm, memmap=True, mode='denywrite') as hdu: dxas = hdu[0].header['CDELT1'] * -1 * u.deg dyas = hdu[0].header['CDELT2'] * u.deg nx, ny = hdu[0].data[0, 0, :, :].shape[0], hdu[0].data[0, 0, :, :].shape[1] old_beam = Beam.from_fits_header(hdu[0].header) datadict = { 'image': hdu[0].data[0, 0, :, :], 'header': hdu[0].header, 'oldbeam': old_beam, 'nx': nx, 'ny': ny, 'dx': dxas, 'dy': dxas } return datadict
def conv_model(model_image, clean_beam): if isinstance(model_image, BaseSpectralCube): model = model_image else: model = SpectralCube.read(model_image, format='casa_image') beam = clean_beam pix_scale = model.header['CDELT2'] * u.deg pix_scale = pix_scale.to(u.arcsec) clean_beam_kernel = beam.as_kernel(pix_scale) omega_beam = beam.sr omega_pix = pix_scale.to('rad')**2 npix_beam = (omega_beam / omega_pix).value # should we just use a delta function rather than try to hack correct pixel area? # alternately, we could deconvolve a pixel size. # What is technically correct? # What does CASA do? (scary question) fwhm_gauss_pix = (4 * np.log(2) / np.pi)**0.5 * pix_scale pix_beam = Beam(fwhm_gauss_pix, fwhm_gauss_pix, 0 * u.deg) model = model.with_beam(pix_beam) conv = model.convolve_to(beam) * npix_beam return conv
def fixExtraHERAfromAdam(fitsimage, beam=15.0): ''' Purpose: fix up extra HERA data from Adam ''' # switch header from M/S to m/s to fix up wcs read errors with SpectralCube f = fits.open(fitsimage) f[0].header['CUNIT3'] = 'm/s' newimage = fitsimage.replace('.fits', '_fixed.fits') f.writeto(newimage, overwrite=True) f.close() # open image cube = SpectralCube.read(newimage) # switch to km/s cube_kms = cube.with_spectral_unit(u.km / u.s) # smooth newBeam = Beam(beam * u.arcsec) smoothCube = cube_kms.convolve_to(newBeam) # write out smoothCube.write(newimage.replace('.fits', '_10kms_gauss15.fits'), overwrite=True)
def test_beams_convolution(): cube, data = cube_and_raw('455_delta_beams.fits') # 1" convolved with 1.5" -> 1.8027.... target_beam = Beam(1.802775637731995*u.arcsec, 1.802775637731995*u.arcsec, 0*u.deg) conv_cube = cube.convolve_to(target_beam) pixscale = wcs.utils.proj_plane_pixel_area(cube.wcs.celestial)**0.5*u.deg for ii,bm in enumerate(cube.beams): expected = target_beam.deconvolve(bm).as_kernel(pixscale, x_size=5, y_size=5) np.testing.assert_almost_equal(expected.array, conv_cube.filled_data[ii,:,:].value)
def identify_bad_beams(self, threshold, reference_beam=None, criteria=['sr', 'major', 'minor'], mid_value=np.nanmedian): """ Mask out any layers in the cube that have beams that differ from the central value of the beam by more than the specified threshold. Parameters ---------- threshold : float Fractional threshold reference_beam : Beam A beam to use as the reference. If unspecified, ``mid_value`` will be used to select a middle beam criteria : list A list of criteria to compare. Can include 'sr','major','minor','pa' or any subset of those. mid_value : function The function used to determine the 'mid' value to compare to. This will identify the middle-valued beam area/major/minor/pa. Returns ------- includemask : np.array A boolean array where ``True`` indicates the good beams """ includemask = np.ones(self.unmasked_beams.size, dtype='bool') all_criteria = {'sr', 'major', 'minor', 'pa'} if not set.issubset(set(criteria), set(all_criteria)): raise ValueError("Criteria must be one of the allowed options: " "{0}".format(all_criteria)) props = { prop: u.Quantity([getattr(beam, prop) for beam in self.unmasked_beams]) for prop in all_criteria } if reference_beam is None: reference_beam = Beam(major=mid_value(props['major']), minor=mid_value(props['minor']), pa=mid_value(props['pa'])) for prop in criteria: val = props[prop] mid = getattr(reference_beam, prop) diff = np.abs((val - mid) / mid) assert diff.shape == includemask.shape includemask[diff > threshold] = False return includemask
def test_single_gray_hole(): one_gray_hole = add_holes((200, 200), hole_level=100, nholes=1) test_gray_hole = Projection(one_gray_hole, wcs=wcs.WCS()) test_bubble = BubbleFinder2D(test_gray_hole, beam=Beam(10), channel=0, sigma=40) test_bubble.multiscale_bubblefind(edge_find=False)
def fixNRO(fitsimage): ''' fix up NRO data ''' cube = SpectralCube.read(fitsimage) # add beam beam_cube = cube.with_beam(Beam(15.0 * u.arcsec)) beam_cube.write(fitsimage.replace('.FITS', '_fixed.fits'), overwrite=True)
def find_beam_properties(hdr): ''' Try to read beam properties from a header. Uses radio_beam when installed. Parameters ---------- hdr : `~astropy.io.fits.Header` FITS header. Returns ------- bmaj : `~astropy.units.Quantity` Major axis of the beam in degrees. bmin : `~astropy.units.Quantity` Minor axis of the beam in degrees. If this cannot be read from the header, assumes `bmaj=bmin`. bpa : `~astropy.units.Quantity` Position angle of the major axis. If this cannot read from the header, assumes an angle of 0 deg. ''' if RADIO_BEAM_INSTALL: try: beam = Beam.from_fits_header(hdr) bmaj = beam.major.to(u.deg) bmin = beam.minor.to(u.deg) bpa = beam.pa.to(u.deg) except NoBeamException: bmaj = None bmin = None bpa = None else: if not isinstance(hdr, fits.Header): raise TypeError("Header is not a FITS header.") if "BMAJ" in hdr: bmaj = hdr["BMAJ"] * u.deg else: warn("Cannot find 'BMAJ' in the header. Try installing" " the `radio_beam` package for loading header" " information.") bmaj = None if "BMIN" in hdr: bmin = hdr["BMIN"] * u.deg else: warn("Cannot find 'BMIN' in the header. Assuming circular beam.") bmin = bmaj if "BPA" in hdr: bpa = hdr["BPA"] * u.deg else: warn("Cannot find 'BPA' in the header. Assuming PA of 0.") bpa = 0 * u.deg return bmaj, bmin, bpa
def convolve_sky_byfactor(cube, factor, savename=None, edgetrim_width=5, downsample=True, **kwargs): factor = factor * 1.0 if not isinstance(cube, SpectralCube): cube = SpectralCube.read(cube) if edgetrim_width is not None: cube = edge_trim(cube, trim_width=edgetrim_width) hdr = cube.header # sanity check if hdr['CUNIT1'] != hdr['CUNIT2']: print "[ERROR]: the axis units for the do not match each other!" return None beamunit = getattr(u, hdr['CUNIT1']) bmaj = hdr['BMAJ'] * beamunit * factor bmin = hdr['BMIN'] * beamunit * factor pa = hdr['BPA'] beam = Beam(major=bmaj, minor=bmin, pa=pa) # convolve cnv_cube = convolve_sky(cube, beam, **kwargs) if cnv_cube.fill_value is not np.nan: cnv_cube = cnv_cube.with_fill_value(np.nan) #cnv_cube = cnv_cube.with_fill_value(0.0) if downsample: # regrid the convolved cube nhdr = FITS_tools.downsample.downsample_header(hdr, factor=factor, axis=1) nhdr = FITS_tools.downsample.downsample_header(nhdr, factor=factor, axis=2) nhdr['NAXIS1'] = int(np.rint(hdr['NAXIS1'] / factor)) nhdr['NAXIS2'] = int(np.rint(hdr['NAXIS2'] / factor)) newcube = cnv_cube.reproject(nhdr, order='bilinear') # newcube = cnv_cube.reproject(nhdr, order='bicubic') else: newcube = cnv_cube if savename is not None: newcube.write(savename, overwrite=True) return newcube
def test_nocelestial_convolution_2D_fail(data_255_delta, use_dask): cube, data = cube_and_raw(data_255_delta, use_dask=use_dask) proj = cube.moment0(axis=1) test_beam = Beam(1.0 * u.arcsec) with pytest.raises(WCSCelestialError, match="WCS does not contain two spatial axes."): proj.convolve_to(test_beam)
def main(pool, args, verbose=False): """Main script """ # Fix up outdir outdir = args.outdir if outdir is not None: if outdir[-1] == '/': outdir = outdir[:-1] else: outdir = '.' # Get file list files = glob(args.infile) if files == []: raise Exception('No files found!') # Parse args bmaj = args.bmaj bmin = args.bmin bpa = args.bpa # Find largest bmax big_beam = getmaxbeam(files, verbose=verbose) # Set to largest if bpa is None and bmin is None and bmaj is None: bpa = big_beam.pa.to(u.deg) else: bpa = 0 * u.deg if bmaj is None: bmaj = round_up(big_beam.major.to(u.arcsec)) elif bmaj * u.arcsec < round_up(big_beam.major.to(u.arcsec)): raise Exception('Selected BMAJ is too small!') else: bmaj *= u.arcsec if bmin is None: bmin = round_up(big_beam.minor.to(u.arcsec)) elif bmin * u.arcsec < round_up(big_beam.minor.to(u.arcsec)): raise Exception('Selected BMIN is too small!') else: bmin *= u.arcsec new_beam = Beam(bmaj, bmin, bpa) if verbose: print(f'Final beam is', new_beam) inputs = [[file, outdir, new_beam, args, verbose] for i, file in enumerate(files)] output = list(pool.map(worker, inputs)) if verbose: print('Done!')
def convolve_Vlsr(V_lsr, header): """ Convolve Vlsr map with beam in header """ pixscale=np.abs(header['cdelt1']) if header['cunit1'] == 'arcsec': pixscale *= u.arcsec else: pixscale *= u.deg my_beam = Beam.from_fits_header(header) my_beam_kernel = my_beam.as_kernel(pixscale) return convolve(V_lsr, my_beam_kernel, boundary='fill', fill_value=np.nan)
def test_projection_with_beam(): exp_beam = Beam(1.0 * u.arcsec) proj, hdu = load_projection("55.fits") # uses from_hdu, which passes beam as kwarg assert proj.beam == exp_beam assert proj.meta['beam'] == exp_beam # load beam from meta exp_beam = Beam(1.5 * u.arcsec) meta = {"beam": exp_beam} new_proj = Projection(hdu.data, wcs=proj.wcs, meta=meta) assert new_proj.beam == exp_beam assert new_proj.meta['beam'] == exp_beam # load beam from given header exp_beam = Beam(2.0 * u.arcsec) header = hdu.header.copy() header = exp_beam.attach_to_header(header) new_proj = Projection(hdu.data, wcs=proj.wcs, header=header, read_beam=True) assert new_proj.beam == exp_beam assert new_proj.meta['beam'] == exp_beam # load beam from beam object exp_beam = Beam(3.0 * u.arcsec) header = hdu.header.copy() del header["BMAJ"], header["BMIN"], header["BPA"] new_proj = Projection(hdu.data, wcs=proj.wcs, header=header, beam=exp_beam) assert new_proj.beam == exp_beam assert new_proj.meta['beam'] == exp_beam # Slice the projection with a beam and check it's still there assert new_proj[:1, :1].beam == exp_beam
def test_nocelestial_convolution_2D_fail(): cube, data = cube_and_raw('255_delta.fits') proj = cube.moment0(axis=1) test_beam = Beam(1.0 * u.arcsec) with pytest.raises(WCSCelestialError) as exc: proj.convolve_to(test_beam) assert exc.value.args[0] == ("WCS does not contain two spatial axes.")
def beam_struct(beam, scale, pixscale, return_beam=False): ''' Return a beam structure. ''' if not _radio_beam_flag: raise ImportError("radio_beam must be installed to return a beam" " structure.") if scale == 1: scale_beam = beam else: scale_beam = Beam(major=scale * beam.major, minor=scale * beam.minor, pa=beam.pa) struct = scale_beam.as_tophat_kernel(pixscale).array struct = (struct > 0).astype(int) if return_beam: return struct, scale_beam return struct
def test_gauss_hole(): one_gauss_hole, params = add_gaussian_holes(np.ones((200, 200)), nholes=1, return_info=True) test_gauss_hole = Projection(one_gauss_hole, wcs=wcs.WCS()) test_bubble = BubbleFinder2D(test_gauss_hole, beam=Beam(10), channel=0, sigma=0.05) test_bubble.multiscale_bubblefind(edge_find=True) test_bubble.visualize_regions(edges=True)
def smallest_beam(beams, includemask=None): """ Returns the smallest beam (by area) in a list of beams. """ from radio_beam import Beam major, minor, pa = beam_props(beams, includemask) smallest_idx = (major * minor).argmin() new_beam = Beam(major=major[smallest_idx], minor=minor[smallest_idx], pa=pa[smallest_idx]) return new_beam
def test_pspec(plotname="pspec_rnoise_beamsmooth_apodizetukey.pdf", size=256, powerlaw=3., run_kwargs={ 'verbose': False, 'apodize_kernel': 'tukey' }, plot_kwargs={'fit_color': 'black'}, beam_smooth=True, pixel_scale=2 * u.arcsec, bmin=8.09 * u.arcsec, bmaj=10.01 * u.arcsec, bpa=-12.9 * u.deg, restfreq=1.4 * u.GHz, bunit=u.K): from spectral_cube import Projection from radio_beam import Beam rnoise_img = make_extended(size, powerlaw) # Create a FITS HDU rnoise_hdu = create_fits_hdu(rnoise_img, 2 * u.arcsec, 2 * u.arcsec, rnoise_img.shape, 1.4 * u.GHz, u.K) pspec = PowerSpectrum(rnoise_hdu) if beam_smooth: pencil_beam = Beam(0 * u.deg) rnoise_proj = Projection.from_hdu(rnoise_hdu).with_beam(pencil_beam) new_beam = Beam(bmaj, bmin, bpa) rnoise_conv = rnoise_proj.convolve_to(new_beam) # hdr = fits.Header(header) # rnoise_hdu = fits.PrimaryHDU(rnoise_img, header=hdr) pspec = PowerSpectrum(rnoise_conv) pspec.run(**run_kwargs) pspec.plot_fit(save_name=plotname, **plot_kwargs) return pspec
def test_beams_convolution_equal(): cube, data = cube_and_raw('522_delta_beams.fits') # Only checking that the equal beam case is handled correctly. # Fake the beam in the first channel. Then ensure that the first channel # has NOT been convolved. target_beam = Beam(1.0 * u.arcsec, 1.0 * u.arcsec, 0.0 * u.deg) cube.beams[0] = target_beam conv_cube = cube.convolve_to(target_beam) np.testing.assert_almost_equal(cube.filled_data[0].value, conv_cube.filled_data[0].value)
def try_load_beams(data): ''' Try loading a beam table from a FITS HDU list. ''' try: from radio_beam import Beam except ImportError: warnings.warn("radio_beam is not installed. No beam " "can be created.", ImportError ) if isinstance(data, fits.BinTableHDU): if 'BPA' in data.data.names: beam_table = data.data return beam_table else: raise ValueError("No beam table found") elif isinstance(data, fits.HDUList): for ihdu, hdu_item in enumerate(data): if isinstance(hdu_item, (fits.PrimaryHDU, fits.ImageHDU)): beam = try_load_beams(hdu_item.header) elif isinstance(hdu_item, fits.BinTableHDU): if 'BPA' in hdu_item.data.names: beam_table = hdu_item.data return beam_table try: # if there was a beam in a header, but not a beam table return beam except NameError: # if the for loop has completed, we didn't find a beam table raise ValueError("No beam table found") elif isinstance(data, (fits.PrimaryHDU, fits.ImageHDU)): return try_load_beams(data.header) elif isinstance(data, fits.Header): try: beam = Beam.from_fits_header(data) return beam except Exception as ex: # warnings.warn("Could not parse beam information from header." # " Exception was: {0}".format(ex.__repr__()), # FITSWarning # ) # Avoid warning since cubes don't have a beam # Warning now provided when `SpectralCube.beam` is None beam = None else: raise ValueError("How did you get here? This is some sort of error.")
def find_beam_properties(hdr): ''' Try to read beam properties from a header. Uses radio_beam when installed. Parameters ---------- hdr : `~astropy.io.fits.Header` FITS header. Returns ------- bmaj : `~astropy.units.Quantity` Major axis of the beam in degrees. bmin : `~astropy.units.Quantity` Minor axis of the beam in degrees. If this cannot be read from the header, assumes `bmaj=bmin`. bpa : `~astropy.units.Quantity` Position angle of the major axis. If this cannot read from the header, assumes an angle of 0 deg. ''' if RADIO_BEAM_INSTALL: beam = Beam.from_fits_header(hdr) bmaj = beam.major.to(u.deg) bmin = beam.minor.to(u.deg) bpa = beam.pa.to(u.deg) else: if not isinstance(hdr, fits.Header): raise TypeError("Header is not a FITS header.") if "BMAJ" in hdr: bmaj = hdr["BMAJ"] * u.deg else: raise ValueError("Cannot find 'BMAJ' in the header. Try installing" " the `radio_beam` package for loading header" " information.") if "BMIN" in hdr: bmin = hdr["BMIN"] * u.deg else: warn("Cannot find 'BMIN' in the header. Assuming circular beam.") bmin = bmaj if "BPA" in hdr: bpa = hdr["BPA"] * u.deg else: warn("Cannot find 'BPA' in the header. Assuming PA of 0.") bpa = 0 * u.deg return bmaj, bmin, bpa
def try_load_beam(header): ''' Try loading a beam from a FITS header. ''' try: beam = Beam.from_fits_header(header) return beam except Exception as ex: # We don't emit a warning if no beam was found since it's ok for # cubes to not have beams if 'No BMAJ' not in str(ex): warnings.warn("Could not parse beam information from header." " Exception was: {0}".format(ex.__repr__()))
def test_ondespectrum_with_beam(): exp_beam = Beam(1.0 * u.arcsec) test_wcs_1 = WCS(naxis=1) spec = OneDSpectrum(twelve_qty_1d, wcs=test_wcs_1) # load beam from meta meta = {"beam": exp_beam} new_spec = OneDSpectrum(spec.data, wcs=spec.wcs, meta=meta) assert new_spec.beam == exp_beam assert new_spec.meta['beam'] == exp_beam # load beam from given header hdu = spec.hdu exp_beam = Beam(2.0 * u.arcsec) header = hdu.header.copy() header = exp_beam.attach_to_header(header) new_spec = OneDSpectrum(hdu.data, wcs=spec.wcs, header=header, read_beam=True) assert new_spec.beam == exp_beam assert new_spec.meta['beam'] == exp_beam # load beam from beam object exp_beam = Beam(3.0 * u.arcsec) header = hdu.header.copy() new_spec = OneDSpectrum(hdu.data, wcs=spec.wcs, header=header, beam=exp_beam) assert new_spec.beam == exp_beam assert new_spec.meta['beam'] == exp_beam # Slice the spectrum with a beam and check it's still there assert new_spec[:1].beam == exp_beam
def remove_small_regions(self, area_threshold=None, beam=None, verbose=False): ''' Remove 2D regions (per channel) based on their area. By default, this removed regions smaller than the beam area. Parameters ---------- area_threshold : float, optional Minimum pixel area to keep. Overrides beam argument. beam : radio_beam.Beam, optional Provide a Beam object to define the area threshold. By default, a Beam object will be created from the information in the cube WCS. Specifying a Beam object will override using the default Beam object from the cube WCS. ''' self.log_and_backup(self.remove_small_regions) # Attempt to get beam area from cube WCS info. if area_threshold is None: if beam is None: beam = Beam.from_fits_header(self._linked_data.header) # Get pixelscale, add unit on (ignore the per pixel) # Eventually the unit should be included in get_pixel_scales # but this requires additional workarounds when used for Beam # objects pixscale = get_pixel_scales(self._wcs) # Now get the pixel beam area area_threshold = \ np.count_nonzero(beam.as_tophat_kernel(pixscale).array > 0) def area_thresh_func(arr, size_thresh): remove_small_objects(arr, min_size=size_thresh, connectivity=arr.ndim, in_place=True) return arr self.reject_region(area_thresh_func, iteraxis='spectral', func_args=(area_threshold), log_call=False, verbose=verbose) return self
def convolve_Vlsr(V_lsr, header): """ It Convolves a pure theoretical Vlsr map with a requested beam. The beam is setup using the FITS header of the expected observation. The convolution would mimick (at least at first order) the effect of a finite beam size in the observations. The header is also used to convert the beam into pixel units before convolving the map param : Vlsr : image with Velocity map to be convolved. It handles astropy.units. header : FITS header with beam and pixel size information TODO: -pass a Beam structure instead of the FITS header, to make it more flexible """ from astropy.convolution import convolve from radio_beam import Beam pixscale=np.abs(header['cdelt1'])*u.Unit(header['cunit1']) my_beam = Beam.from_fits_header(header) my_beam_kernel = my_beam.as_kernel(pixscale) return convolve(V_lsr, my_beam_kernel, boundary='fill', fill_value=np.nan)
def load_beam(self, beam=None): ''' Try loading the beam from the header or a given object. Parameters ---------- beam : `~radio_beam.Beam`, optional The beam. ''' if beam is None: if hasattr(self, "_header"): try: beam = Beam.from_fits_header(self.header) self._beam = beam except NoBeamException: warn("Header missing beam information.") else: warn("No header available. Cannot load beam.") else: if not isinstance(beam, Beam): raise TypeError("beam must be a radio_beam.Beam object.") self._beam = beam
import numpy as np from astropy.io import fits from astropy.wcs import WCS import matplotlib.pyplot as plt from astropy.visualization import AsinhStretch from astropy.visualization.mpl_normalize import ImageNormalize from radio_beam import Beam from paths import fourteenB_HI_data_path, paper1_figures_path from constants import moment0_name, moment1_name, hi_freq moment0 = fits.open(fourteenB_HI_data_path(moment0_name))[0] beam = Beam.from_fits_header(moment0.header) moment0_Kkm_s = beam.jtok(hi_freq).value * moment0.data / 1000. ax = plt.subplot(111, projection=WCS(moment0.header)) im = ax.imshow(moment0_Kkm_s, origin='lower', interpolation='nearest', norm=ImageNormalize(vmin=-0.001, vmax=np.nanmax(moment0_Kkm_s), stretch=AsinhStretch())) ax.set_ylabel("DEC (J2000)") ax.set_xlabel("RA (J2000)") cbar = plt.colorbar(im) cbar.set_label(r"Intensity (K km s$^{-1}$)")
if __name__ == "__main__": import matplotlib.pyplot as p from paths import (fourteenB_HI_data_path, arecibo_HI_data_path, c_hi_analysispath, paper1_figures_path, data_path) from constants import moment0_name, lwidth_name from galaxy_params import gal lwidth_hdu = fits.open(fourteenB_HI_data_path(lwidth_name))[0] lwidth = Projection(lwidth_hdu.data, wcs=WCS(lwidth_hdu.header), unit=u.m / u.s) lwidth.meta["beam"] = Beam.from_fits_header(lwidth_hdu.header) # Create a radial profile of the HI vel disp out to 8 kpc. # Beyond 8 kpc, noise is dominant. It may be some reflection of the # warp, but I don't trust it right now. rs, sd, sd_sigma = radial_profile(gal, lwidth, max_rad=8 * u.kpc) sd = sd.to(u.km / u.s) sd_sigma = sd_sigma.to(u.km / u.s) p.errorbar(rs.value, sd.value, yerr=sd_sigma.value, fmt="-", color="b", drawstyle='steps-mid') p.xlabel("R (kpc)") p.ylabel("HI Velocity Dispersion (km/s)") p.grid()
if fail: warn("Fail flag was raised. Check the output") # raise ValueError("Fit failed.") return fit, err, model, profile if __name__ == "__main__": from analysis.paths import (fourteenB_HI_data_path, paper1_figures_path, iram_co21_data_path) from analysis.constants import moment0_name from analysis.galaxy_params import gal mom0_fits = fits.open(fourteenB_HI_data_path(moment0_name))[0] beam = Beam.from_fits_header(mom0_fits.header) mom0 = Projection(mom0_fits.data * beam.jtok(hi_freq) / 1000. * u.km / u.s, wcs=WCS(mom0_fits.header)) mom0.meta['beam'] = beam # Create the bubble mask instead of letting FilFinder to do it. bub = BubbleFinder2D(mom0, sigma=80. * beam.jtok(hi_freq) / 1000.) # fils = fil_finder_2D(mom0.value, mom0.header, 10, distance=0.84e6) # fils.mask = ~(bub.mask.copy()) # fils.medskel() # fils.analyze_skeletons() # # So at least on of the radial profiles fails. BUT the second fit is to a # # skeleton that is essentially the entire disk, so plot without interactivity # # and save the plot and the parameters shown in verbose mode.
from astropy.io import fits from astropy import coordinates from astropy import units as u from astropy import wcs import FITS_tools import reproject import paths import image_registration from radio_beam import Beam from astropy import convolution import gaussfitter epoch3 = fits.open(paths.dpath("W51Ku_BDarray_continuum_2048_both_uniform.hires.clean.image.fits")) beam3 = Beam.from_fits_header(epoch3[0].header) epoch3[0].data = epoch3[0].data.squeeze() wcs3 = wcs.WCS(epoch3[0].header).sub([wcs.WCSSUB_CELESTIAL]) epoch3header = wcs3.to_header() epoch3header['NAXIS'] = 2 epoch3header['NAXIS1'] = epoch3[0].data.shape[1] epoch3header['NAXIS2'] = epoch3[0].data.shape[0] kernel = (0.3*u.arcsec).to(u.deg) pixscale = (wcs3.pixel_scale_matrix.diagonal()**2).sum()**0.5 * u.deg print('pix kernel size: {0}'.format(kernel/pixscale)) smoothed3 = convolution.convolve_fft(epoch3[0].data, convolution.Gaussian2DKernel(kernel/pixscale)) diff3sm = epoch3[0].data - smoothed3 diff3smhdu = fits.PrimaryHDU(data=diff3sm, header=epoch3header) diff3smhdu.writeto(paths.dpath("Kuband_Epoch3sm-Epoch3.fits"), clobber=True, output_verify='fix')
p.axvline(np.where(mask[:, i, j])[0][0]) p.plot(smooth_cube[:, i, j] * mask[:, i, j], 'bD') # p.vlines(np.where(mask[:, i, j])[0][-1], 0, np.nanmax(spectrum)) # p.vlines(np.where(mask[:, i, j])[0][0], 0, np.nanmax(spectrum)) # p.plot(smoothed * mask[:, i, j], 'bD') p.draw() raw_input("Next spectrum?") p.clf() initial_mask = mask.copy() # The resolution is about 47 arcsec, but this is just 2 pixels across in # the map. I'm going to double this to only include features that are # clearly not noise beam = Beam(major=2 * 47 * u.arcsec) kernel = beam.as_tophat_kernel(pixscale) kernel_pix = (kernel.array > 0).sum() for i in ProgressBar(mask.shape[0]): mask[i] = nd.binary_opening(mask[i], kernel) mask[i] = nd.binary_closing(mask[i], kernel) mask[i] = mo.remove_small_objects(mask[i], min_size=kernel_pix, connectivity=2) mask[i] = mo.remove_small_holes(mask[i], min_size=kernel_pix, connectivity=2) # Each region must contain a point above the peak_snr labels, num = nd.label(mask, np.ones((3, 3, 3))) for n in range(1, num + 1):
def cubefit(region='NGC1333', blorder=1, vmin=5, vmax=15, do_plot=False, snr_min=5.0, multicore=1): """ Fit NH3(1,1), (2,2) and (3,3) cubes for the requested region. It fits all pixels with SNR larger than requested. Initial guess is based on moment maps and neighboring pixels. The fitting can be done in parallel mode using several cores, however, this is dangerous for large regions, where using a good initial guess is important. It stores the result in a FITS cube. TODO: -Store results in hdu list -Improve initial guess Parameters ---------- region : str Name of region to reduce blorder : int order of baseline removed vmin : numpy.float Minimum centroid velocity to plot, in km/s. vmax : numpy.float Maximum centroid velocity to plot, in km/s. do_plot : bool If True, then a map of the region to map is shown. snr_min : numpy.float Minimum signal to noise ratio of the spectrum to be fitted. multicore : int Numbers of cores to use for parallel processing. """ OneOneIntegrated = '{0}/{0}_NH3_11_mom0.fits'.format(region,blorder) OneOneFile = '{0}/{0}_NH3_11_base{1}.fits'.format(region,blorder) RMSFile = '{0}/{0}_NH3_11_base{1}_rms.fits'.format(region,blorder) TwoTwoFile = '{0}/{0}_NH3_22_base{1}.fits'.format(region,blorder) ThreeThreeFile = '{0}/{0}_NH3_33_base{1}.fits'.format(region,blorder) beam11 = Beam.from_fits_header(fits.getheader(OneOneFile)) cube11sc = SpectralCube.read(OneOneFile) cube22sc = SpectralCube.read(TwoTwoFile) errmap11 = fits.getdata(RMSFile) snr = cube11sc.filled_data[:].value/errmap11 peaksnr = np.max(snr,axis=0) rms = np.nanmedian(errmap11) planemask = (peaksnr>snr_min) # *(errmap11 < 0.15) planemask = remove_small_objects(planemask,min_size=40) planemask = opening(planemask,disk(1)) #planemask = (peaksnr>20) * (errmap11 < 0.2) mask = (snr>3)*planemask maskcube = cube11sc.with_mask(mask.astype(bool)) maskcube = maskcube.with_spectral_unit(u.km/u.s,velocity_convention='radio') slab = maskcube.spectral_slab( vmax*u.km/u.s, vmin*u.km/u.s) w11=slab.moment( order=0, axis=0).value peakloc = np.nanargmax(w11) ymax,xmax = np.unravel_index(peakloc,w11.shape) moment1 = slab.moment( order=1, axis=0).value moment2 = (slab.moment( order=2, axis=0).value)**0.5 moment2[np.isnan(moment2)]=0.2 moment2[moment2<0.2]=0.2 maskmap = w11>0.5 cube11 = pyspeckit.Cube(OneOneFile,maskmap=planemask) cube11.unit="K" cube22 = pyspeckit.Cube(TwoTwoFile,maskmap=planemask) cube22.unit="K" cube33 = pyspeckit.Cube(ThreeThreeFile,maskmap=planemask) cube33.unit="K" cubes = pyspeckit.CubeStack([cube11,cube22,cube33],maskmap=planemask) cubes.unit="K" guesses = np.zeros((6,)+cubes.cube.shape[1:]) moment1[moment1<vmin] = vmin+0.2 moment1[moment1>vmax] = vmax-0.2 guesses[0,:,:] = 12 # Kinetic temperature guesses[1,:,:] = 3 # Excitation Temp guesses[2,:,:] = 14.5 # log(column) guesses[3,:,:] = moment2 # Line width / 5 (the NH3 moment overestimates linewidth) guesses[4,:,:] = moment1 # Line centroid guesses[5,:,:] = 0.5 # F(ortho) - ortho NH3 fraction (fixed) if do_plot: import matplotlib.pyplot as plt plt.imshow( w11, origin='lower') plt.show() F=False T=True print('start fit') cubes.fiteach(fittype='ammonia', guesses=guesses, integral=False, verbose_level=3, fixed=[F,F,F,F,F,T], signal_cut=2, limitedmax=[F,F,F,F,T,T], maxpars=[0,0,0,0,vmax,1], limitedmin=[T,T,T,T,T,T], minpars=[5,2.8,12.0,0.04,vmin,0], start_from_point=(xmax,ymax), use_neighbor_as_guess=True, position_order = 1/peaksnr, errmap=errmap11, multicore=multicore) fitcubefile = fits.PrimaryHDU(data=np.concatenate([cubes.parcube,cubes.errcube]), header=cubes.header) fitcubefile.header.update('PLANE1','TKIN') fitcubefile.header.update('PLANE2','TEX') fitcubefile.header.update('PLANE3','COLUMN') fitcubefile.header.update('PLANE4','SIGMA') fitcubefile.header.update('PLANE5','VELOCITY') fitcubefile.header.update('PLANE6','FORTHO') fitcubefile.header.update('PLANE7','eTKIN') fitcubefile.header.update('PLANE8','eTEX') fitcubefile.header.update('PLANE9','eCOLUMN') fitcubefile.header.update('PLANE10','eSIGMA') fitcubefile.header.update('PLANE11','eVELOCITY') fitcubefile.header.update('PLANE12','eFORTHO') fitcubefile.header.update('CDELT3',1) fitcubefile.header.update('CTYPE3','FITPAR') fitcubefile.header.update('CRVAL3',0) fitcubefile.header.update('CRPIX3',1) fitcubefile.writeto("{0}_parameter_maps.fits".format(region),clobber=True)
def avg_fwhm(beam): return np.sqrt(beam.major.to(u.arcsec) * beam.minor.to(u.arcsec)) parameters = ["CASAVer", "Model", "Mask", "AllFields", "MScale", "Tclean"] # Load in the mask mask_hdu = fits.open(append_path("M33_14B-088_HI_mask_channel_330.fits"))[0] mask = mask_hdu.data.squeeze() mask = mask[::-1, ::-1] == 1 low_hdu = fits.open(append_path("M33_14B-088_HI_model_channel_330.fits"))[0] model = low_hdu.data.squeeze() model = model[::-1, ::-1] sd_beam = Beam.from_fits_header(append_path("M33_14B-088_HI_model_channel_330.fits")) fft_sd = np.fft.fftshift(np.fft.fft2(np.nan_to_num(model))) # Also load in the original Arecibo channel that has not been regridded. low_hdu_orig = \ fits.open(append_path("M33_14B-088_HI_model_original_arecibo.fits"))[0] # The commented out sections were for ensuring that the model matched # regridded versions using FITS_tools and reproject. On the large scales that # matter, the answer is yes they do match. # regrid_model, footprint = reproject_interp(low_hdu_orig, low_hdu.header) # regrid_model_fitstools = hcongrid(low_hdu_orig.data, low_hdu_orig.header, # low_hdu.header) regrid_mask = reproject_interp(mask_hdu, low_hdu_orig.header)[0] regrid_mask[np.isnan(regrid_mask)] = 0.0 regrid_mask = regrid_mask == 1.0
import pyspeckit import astropy.io.fits as fits import numpy as np import os from spectral_cube import SpectralCube import signal_id from radio_beam import Beam import astropy.constants as con import astropy.units as u OneOneIntegrated = 'NGC1333_W11.fits' OneOneFile = 'NGC1333_ABCDEFGH_NH3_11_all_blsub.rg.fits' TwoTwoFile = 'NGC1333_ABCDEFGH_NH3_22_all_blsub.fits' ThreeThreeFile = 'NGC1333_ABCDEFGH_NH3_33_all_blsub.fits' beam11 = Beam.from_fits_header(fits.getheader(OneOneFile)) cube11sc = SpectralCube.read(OneOneFile) cube22sc = SpectralCube.read(TwoTwoFile) noisy = signal_id.noise.Noise(cube11sc) noisy.estimate_noise(spectral_flat=True,niter=2) errmap11 = (noisy.spatial_norm*noisy.scale) rms = np.nanmedian(errmap11) mask = (noisy.snr>5)*(noisy.spatial_norm<2.5) maskcube = cube11sc.with_mask(mask) maskcube = maskcube.with_spectral_unit(u.km/u.s,velocity_convention='radio') slab = maskcube#.spectral_slab(5*u.km/u.s,15*u.km/u.s) w11=slab.moment(0,0).value peakloc = np.nanargmax(w11) xmax,ymax = np.unravel_index(peakloc,w11.shape) moment1 = slab.moment(1,0).value
# Load in the mask ia.open(append_path("M33_14B-088_HI_mask_channel_330.image")) mask = ia.torecord()["imagearray"].squeeze() > 0 ia.close() # For some reason, both axes need to be reversed mask = mask[::-1, ::-1] # Load in the model ia.open(append_path("M33_14B-088_HI_model_channel_330.image")) model = ia.torecord()["imagearray"].squeeze() ia.close() model = model[::-1, ::-1] # model[~mask] = np.NaN sd_beam = \ Beam.from_casa_image(append_path("M33_14B-088_HI_model_channel_330.image")) folders = glob(append_path("14B-088_HI_LSRK.ms.contsub_channel_1000.CASAVer*")) parameter_array = np.zeros((len(parameters), len(folders))) parameter_table = dict.fromkeys(parameters) for key in parameter_table: parameter_table[key] = [] # Values to extract out. parameter_table["std"] = [] parameter_table["sum"] = [] parameter_table["median"] = [] parameter_table["peak_res"] = []
def append_path(path): return os.path.join(data_path, path) parameters = ["CASAVer", "Model", "Mask", "AllFields", "MScale", "Tclean"] # Load in the mask mask = fits.open(append_path("M33_14B-088_HI_mask_channel_330.fits"))[0].data.squeeze() mask = mask[::-1, ::-1] == 1 model = fits.open(append_path("M33_14B-088_HI_model_channel_330.fits"))[0].data.squeeze() low_hdu = fits.open(append_path("M33_14B-088_HI_model_channel_330.fits"))[0] # For some reason, both axes need to be reversed model = model[::-1, ::-1] sd_beam = Beam.from_fits_header(append_path("M33_14B-088_HI_model_channel_330.fits")) fft_sd = np.fft.fftshift(np.fft.fft2(model)) # Arecibo FWHM lowresfwhm = (3.8 * u.arcmin).to(u.arcsec) # Grid scaling used. pixscale = 3 * u.arcsec # Image shape nax2, nax1 = model.shape # High scale factor highresscalefactor = 1.0 # Low scale factor lowresscalefactor = 1.0 # x-axis unit
from radio_beam import Beam from astropy.io import fits import os from paths import (fourteenB_HI_data_path, arecibo_HI_data_path, c_hi_analysispath, paper1_figures_path, data_path) from constants import hi_freq, moment0_name from galaxy_params import gal mom0_hdu = fits.open(fourteenB_HI_data_path(moment0_name))[0] mom0 = Projection(mom0_hdu.data, wcs=WCS(mom0_hdu.header), unit=u.Jy * u.m / u.s) mom0.meta["beam"] = Beam.from_fits_header(mom0_hdu.header) # Bin size in pc dr = 100 * u.pc # Create a radial profile of HI rs, sd, sd_sigma = surfdens_radial_profile(gal, mom0=mom0, dr=dr, restfreq=hi_freq) rs_n, sd_n, sd_sigma_n = \ surfdens_radial_profile(gal, mom0=mom0, pa_bounds=Angle([0.5 * np.pi * u.rad, -0.5 * np.pi * u.rad]), dr=dr, restfreq=hi_freq) rs_s, sd_s, sd_sigma_s = \ surfdens_radial_profile(gal, mom0=mom0, pa_bounds=Angle([-0.5 * np.pi * u.rad,
def cubefit(region='IC348', do_plot=True, snr_min=5.0, multicore=1): """ Fit NH3(1,1) and (2,2) cubes for the requested region. It fits all pixels with SNR larger than requested. Initial guess is based on moment maps and neighboring pixels. The fitting can be done in parallel mode using several cores, however, this is dangerous for large regions, where using a good initial guess is important. It stores the result in a FITS cube. TODO: -Store results in hdu list -Improve initial guess Parameters ---------- region : str Name of region to reduce blorder : int order of baseline removed do_plot : bool If True, then a map of the region to map is shown. snr_min : numpy.float Minimum signal to noise ratio of the spectrum to be fitted. multicore : int Numbers of cores to use for parallel processing. """ if region == 'IC348': OneOneFile = 'IC348mm/IC348mm-11_cvel_clean_rob05.fits' TwoTwoFile = 'IC348mm/IC348mm-11_cvel_clean_rob05.fits' vmin=7.4 vmax=10.0 rms=3e-3 elif region == 'IRAS03282': OneOneFile = 'IRAS03282/IRAS03282-11_cvel_clean_rob05.fits' TwoTwoFile = 'IRAS03282/IRAS03282-11_cvel_clean_rob05.fits' vmin=6.0 vmax=8.5 rms=2.5e-3 elif region == 'L1451mm': OneOneFile = 'L1451mm/L1451MM-11_cvel_clean_rob05.fits' TwoTwoFile = 'L1451mm/L1451MM-11_cvel_clean_rob05.fits' vmin=3.2 vmax=4.9 rms=1.6e-3 else: message('Nothing defined here yet... check the regions') beam11 = Beam.from_fits_header(fits.getheader(OneOneFile)) beam22 = Beam.from_fits_header(fits.getheader(TwoTwoFile)) cube11sc = SpectralCube.read(OneOneFile) cube22sc = SpectralCube.read(TwoTwoFile) xarr11 = SpectroscopicAxis( cube11sc.spectral_axis, refX=freq11, velocity_convention='radio') xarr22 = SpectroscopicAxis( cube22sc.spectral_axis, refX=freq22, velocity_convention='radio') #errmap11 = fits.getdata(RMSFile) vcube11sc = cube11sc.with_spectral_unit(u.km/u.s, rest_value=freq11, velocity_convention='radio') vcube22sc = cube22sc.with_spectral_unit(u.km/u.s, rest_value=freq22, velocity_convention='radio') snr = vcube11sc.filled_data[:].value/rms peaksnr = np.max(snr,axis=0) #rms = np.nanmedian(errmap11) errmap11 = np.full( snr.shape[1:], rms) planemask = (peaksnr>snr_min) # *(errmap11 < 0.15) planemask = remove_small_objects(planemask,min_size=40) planemask = opening(planemask,disk(1)) #planemask = (peaksnr>20) * (errmap11 < 0.2) mask = (snr>3)*planemask maskcube = vcube11sc.with_mask(mask.astype(bool)) slab = maskcube.spectral_slab( vmax*u.km/u.s, vmin*u.km/u.s) w11=slab.moment( order=0, axis=0).value peakloc = np.nanargmax(w11) ymax,xmax = np.unravel_index(peakloc,w11.shape) moment1 = slab.moment( order=1, axis=0).value moment2 = (slab.moment( order=2, axis=0).value)**0.5 moment2[np.isnan(moment2)]=0.2 moment2[moment2<0.2]=0.2 maskmap = w11>0.5 # PySpecKit cube for NH3(1,1) cube11 = pyspeckit.Cube(cube=vcube11sc,maskmap=planemask, xarr=xarr11) #cube11 = pyspeckit.Cube(file=OneOneFile,maskmap=planemask)#, xarr=xarr11) cube11.cube *= beam11.jtok( freq11) cube11.unit="K" # PySpecKit cube for NH3(2,2) cube22 = pyspeckit.Cube(cube=vcube22sc,maskmap=planemask, xarr=xarr22) #cube22 = pyspeckit.Cube(file=TwoTwoFile,maskmap=planemask)#, xarr=xarr22) cube22.cube *= beam22.jtok( freq22) cube22.unit="K" # cubes = pyspeckit.CubeStack([cube11,cube22],maskmap=planemask) # cubes.unit="K" guesses = np.zeros((6,)+cube11.cube.shape[1:]) moment1[moment1<vmin] = vmin+0.2 moment1[moment1>vmax] = vmax-0.2 guesses[0,:,:] = 12 # Kinetic temperature guesses[1,:,:] = 8 # Excitation Temp guesses[2,:,:] = 14.5 # log(column) guesses[3,:,:] = moment2 # Line width / 5 (the NH3 moment overestimates linewidth) guesses[4,:,:] = moment1 # Line centroid guesses[5,:,:] = 0.5 # F(ortho) - ortho NH3 fraction (fixed) if do_plot: import matplotlib.pyplot as plt plt.imshow( w11, origin='lower') plt.show() F=False T=True print('start fit') cube11.fiteach(fittype='ammonia', guesses=guesses, integral=False, verbose_level=3, fixed=[T,F,F,F,F,T], signal_cut=2, limitedmax=[F,F,T,F,T,T], maxpars=[0,0,17.0,0,vmax,1], limitedmin=[T,T,T,T,T,T], minpars=[5,2.8,12.0,0,vmin,0], start_from_point=(xmax,ymax), use_neighbor_as_guess=True, position_order = 1/peaksnr, errmap=errmap11, multicore=multicore) #fitcubefile = fits.PrimaryHDU(data=np.concatenate([cubes.parcube,cubes.errcube]), header=cubes.header) fitcubefile = fits.PrimaryHDU(data=np.concatenate([cube11.parcube,cube11.errcube]), header=cube11.header) fitcubefile.header.update('PLANE1','TKIN') fitcubefile.header.update('PLANE2','TEX') fitcubefile.header.update('PLANE3','COLUMN') fitcubefile.header.update('PLANE4','SIGMA') fitcubefile.header.update('PLANE5','VELOCITY') fitcubefile.header.update('PLANE6','FORTHO') fitcubefile.header.update('PLANE7','eTKIN') fitcubefile.header.update('PLANE8','eTEX') fitcubefile.header.update('PLANE9','eCOLUMN') fitcubefile.header.update('PLANE10','eSIGMA') fitcubefile.header.update('PLANE11','eVELOCITY') fitcubefile.header.update('PLANE12','eFORTHO') fitcubefile.header.update('CDELT3',1) fitcubefile.header.update('CTYPE3','FITPAR') fitcubefile.header.update('CRVAL3',0) fitcubefile.header.update('CRPIX3',1) fitcubefile.writeto("{0}_parameter_maps_snr{1}.fits".format(region,snr_min),clobber=True) convert_param_file(region=region, snr_min=snr_min)
from uvcombine.uvcombine import feather_kernel, fftmerge, feather_compare data_path = os.path.expanduser("~/MyRAID/M33/VLA/14B-088/HI/feather_testing") # high_hdu = fits.open(os.path.join(data_path, "M33_14B-088_HI.clean_channel_820.image_old.fits"))[0] # high_hdu = fits.open(os.path.join(data_path, "14B-088_HI_LSRK.ms.contsub_channel_1514.clean.image.fits"))[0] high_hdu = fits.open(os.path.join(data_path, "M33_14B-088_HI.clean_channel_820.image.fits"))[0] # high_hdu_casa_feather = \ # fits.open(os.path.join(data_path, "M33_14B-088_HI.clean.image.feathered_channel_820.image.fits"))[0] low_hdu = fits.open(os.path.join(data_path, "M33_14B-088_HI_model_channel_844.image.fits"))[0] mask = fits.open(os.path.join(data_path, "M33_14B-088_HI_mask_channel_844.fits"))[0] high_beam = Beam.from_fits_header(high_hdu.header) low_beam = Beam.from_fits_header(low_hdu.header) y_size, x_size = high_hdu.shape pixscale = (3 * u.arcsec).to(u.deg) # Try removing all NaNed regions # slicer = (slice(845, 2133), slice(725, 1615)) slicer = (slice(None), slice(None)) # new_shape = (2133 - 845, 1615 - 725) new_shape = (2560, 2560) # Ensure Arecibo doesn't have negative values or power outside of the VLA map high_data = high_hdu.data.copy()[slicer]