def __init__(self, cube, wcs=None, mask=None, sigma=None, empty_channel=0, keep_threshold_mask=True, distance=None, galaxy_props={}): super(BubbleFinder, self).__init__() if not isinstance(cube, SpectralCube): if wcs is None: raise TypeError("When cube is not a SpectralCube, wcs must be" " given.") cube = SpectralCube(cube, wcs) if mask is not None: cube = cube.with_mask(mask) self.cube = cube self.empty_channel = empty_channel if sigma is None: self.estimate_sigma() else: self.sigma = sigma self.keep_threshold_mask = keep_threshold_mask self._mask = None self.distance = distance self.galaxy_props = galaxy_props
def _spectrum_from_component(self, layer, component, wcs, mask=None): data = SpectralCube(component.data, wcs) if mask is not None: data = data.with_mask(mask) if self._data_operation.currentIndex() == 1: spec_data = data.mean((1, 2)) elif self._data_operation.currentIndex() == 2: spec_data = data.median((1, 2)) else: spec_data = data.sum((1, 2)) spec_data = Spectrum1DRef(spec_data.data, unit=spec_data.unit, dispersion=data.spectral_axis.data, dispersion_unit=data.spectral_axis.unit, wcs=data.wcs, name=layer.label) # Store the relation between the component and the specviz data. If # the data exists, first remove the component from specviz and then # re-add it. if layer in self._specviz_data_cache: old_spec_data = self._specviz_data_cache[layer] dispatch.on_remove_data.emit(old_spec_data) self._specviz_data_cache[layer] = spec_data dispatch.on_add_to_window.emit(data=spec_data, style={'color': layer.style.rgba[:3]})
def load_and_reduce(filename, add_noise=False, rms_noise=0.001, nsig=3): ''' Load the cube in and derive the property arrays. ''' if add_noise: if rms_noise is None: raise TypeError("Must specify value of rms noise.") cube, hdr = getdata(filename, header=True) from scipy.stats import norm cube += norm.rvs(0.0, rms_noise, cube.shape) sc = SpectralCube(data=cube, wcs=WCS(hdr)) mask = LazyMask(np.isfinite, sc) sc = sc.with_mask(mask) else: sc = filename reduc = Mask_and_Moments(sc, scale=rms_noise) reduc.make_mask(mask=reduc.cube > nsig * reduc.scale) reduc.make_moments() reduc.make_moment_errors() return reduc.to_dict()
def _spectrum_from_component(self, layer, component, wcs, mask=None, cid=None): data = SpectralCube(component.data, wcs) if mask is not None: data = data.with_mask(mask) # Update the associated data attribute in the plugin self._spec_ops.spectral_data = data self._spec_ops.component_id = cid if self._data_operation.currentIndex() == 1: spec_data = data.mean((1, 2)) elif self._data_operation.currentIndex() == 2: spec_data = data.median((1, 2)) else: spec_data = data.sum((1, 2)) spec_data = Spectrum1DRef(spec_data.data, unit=spec_data.unit, dispersion=data.spectral_axis.data, dispersion_unit=data.spectral_axis.unit, wcs=data.wcs, name=layer.label) spec_layer = Spectrum1DRefLayer.from_parent(spec_data) # Store the relation between the component and the specviz data. If # the data exists, first remove the component from specviz and then # re-add it. old_spec_layer = self._specviz_data_cache.get(layer) self._specviz_data_cache[layer] = spec_layer if old_spec_layer is None: dispatch.on_add_to_window.emit(layer=spec_layer, style={ 'color': layer.style.rgba[:3], 'line_width': 3 }, vertical_line=True) else: dispatch.replace_layer.emit(old_layer=old_spec_layer, new_layer=spec_layer, style={ 'color': layer.style.rgba[:3], 'line_width': 3 })
def reduce_and_save(filename, add_noise=False, rms_noise=0.001, output_path="", cube_output=None, nsig=3, slicewise_noise=True): ''' Load the cube in and derive the property arrays. ''' if add_noise: if rms_noise is None: raise TypeError("Must specify value of rms noise.") cube, hdr = getdata(filename, header=True) # Optionally scale noise by 1/10th of the 98th percentile in the cube if rms_noise == 'scaled': rms_noise = 0.1*np.percentile(cube[np.isfinite(cube)], 98) from scipy.stats import norm if not slicewise_noise: cube += norm.rvs(0.0, rms_noise, cube.shape) else: spec_shape = cube.shape[0] slice_shape = cube.shape[1:] for i in range(spec_shape): cube[i, :, :] += norm.rvs(0.0, rms_noise, slice_shape) sc = SpectralCube(data=cube, wcs=WCS(hdr)) mask = LazyMask(np.isfinite, sc) sc = sc.with_mask(mask) else: sc = filename reduc = Mask_and_Moments(sc, scale=rms_noise) reduc.make_mask(mask=reduc.cube > nsig * reduc.scale) reduc.make_moments() reduc.make_moment_errors() # Remove .fits from filename save_name = filename.split("/")[-1][:-4] reduc.to_fits(output_path+save_name) # Save the noisy cube too if add_noise: if cube_output is None: reduc.cube.hdu.writeto(output_path+save_name) else: reduc.cube.hdu.writeto(cube_output+save_name)
def warp_ellipse_to_circle(cube, a, b, pa, stop_if_huge=True): ''' Warp a SpectralCube such that the given ellipse is a circle int the warped frame. Since you should **NOT** be doing this with a large cube, we're going to assume that the given cube is a subcube centered in the middle of the cube. This requires a rotation, then scaling. The equivalent matrix is: [b cos PA b sin PA] [-a sin PA a cos PA ]. ''' if cube._is_huge: if stop_if_huge: raise Warning("The cube has the huge flag enabled. Disable " "'stop_if_huge' if you would like to continue " "anyways with the warp.") else: warn("The cube has the huge flag enabled. This may use a lot " "of memory!") # Let NaNs be 0 data = cube.with_fill_value(0.0).filled_data[:].value warped_array = [] for i in range(cube.shape[0]): warped_array.append( nd.zoom(nd.rotate(data[i], np.rad2deg(-pa)), (1, a / b))) warped_array = np.array(warped_array) # We want to mask outside of the original bounds mask = np.ones(data.shape[1:]) warp_mask = \ np.isclose(nd.zoom(nd.rotate(mask, np.rad2deg(-pa)), (1, a / b)), 1) # There's probably a clever way to transform the WCS, but all the # solutions appear to need pyast/starlink. The output of the wrap should # give a radius of b and the spectral dimension is unaffected. # Also this is hidden and users won't be able to use this weird cube # directly warped_cube = SpectralCube(warped_array * cube.unit, cube.wcs) warped_cube = warped_cube.with_mask(warp_mask) return warped_cube
def warp_ellipse_to_circle(cube, a, b, pa, stop_if_huge=True): ''' Warp a SpectralCube such that the given ellipse is a circle int the warped frame. Since you should **NOT** be doing this with a large cube, we're going to assume that the given cube is a subcube centered in the middle of the cube. This requires a rotation, then scaling. The equivalent matrix is: [b cos PA b sin PA] [-a sin PA a cos PA ]. ''' if cube._is_huge: if stop_if_huge: raise Warning("The cube has the huge flag enabled. Disable " "'stop_if_huge' if you would like to continue " "anyways with the warp.") else: warn("The cube has the huge flag enabled. This may use a lot " "of memory!") # Let NaNs be 0 data = cube.with_fill_value(0.0).filled_data[:].value warped_array = [] for i in range(cube.shape[0]): warped_array.append(nd.zoom(nd.rotate(data[i], np.rad2deg(-pa)), (1, a / b))) warped_array = np.array(warped_array) # We want to mask outside of the original bounds mask = np.ones(data.shape[1:]) warp_mask = \ np.isclose(nd.zoom(nd.rotate(mask, np.rad2deg(-pa)), (1, a / b)), 1) # There's probably a clever way to transform the WCS, but all the # solutions appear to need pyast/starlink. The output of the wrap should # give a radius of b and the spectral dimension is unaffected. # Also this is hidden and users won't be able to use this weird cube # directly warped_cube = SpectralCube(warped_array * cube.unit, cube.wcs) warped_cube = warped_cube.with_mask(warp_mask) return warped_cube
def get_best_2comp_residual_cnv(reg, masked=True, window_hwidth=3.5, res_snr_cut=5): # return convolved residual cube. If masked is True, only convolve over where 'excessive' residual # above a peak SNR value of res_snr_cut masked # need a mechanism to make sure reg.ucube.pcubes['1'], reg.ucube.pcubes['2'] exists res_cube = get_best_2comp_residual(reg) best_res = res_cube._data cube_res = SpectralCube(data=best_res, wcs=reg.ucube.pcubes['2'].wcs.copy(), header=reg.ucube.pcubes['2'].header.copy()) if masked: best_rms = UCube.get_rms(res_cube._data) # calculate the peak SNR value of the best-fit residual over the main hyperfine components vmap = reg.ucube.pcubes['1'].parcube[0] # make want to double check that masked cube always masks out nan values res_main_hf = mmg.vmask_cube(res_cube, vmap, window_hwidth=window_hwidth) if res_main_hf.size > 1e7: # to avoid loading entire cube and stress the memory how = 'slice' else: # note: 'auto' currently returns slice for n > 1e8 how = 'auto' # enable huge operations (note: not needed when "how" is chosen wisely, which it should be) res_main_hf.allow_huge_operations = True res_main_hf_snr = res_main_hf.max(axis=0, how=how).value / best_rms res_main_hf.allow_huge_operations = False # mask out residual with SNR values over the cut threshold mask_res = res_main_hf_snr > res_snr_cut mask_res = dilation(mask_res) cube_res_masked = cube_res.with_mask(~mask_res) else: cube_res_masked = cube_res cube_res_cnv = cnvtool.convolve_sky_byfactor(cube_res_masked, factor=reg.cnv_factor, edgetrim_width=None, snrmasked=False, iterrefine=False) cube_res_cnv = cube_res_cnv.with_spectral_unit(u.km / u.s, velocity_convention='radio') return cube_res_cnv
def load_and_reduce(filename, add_noise=False, rms_noise=0.001, nsig=3, slicewise_noise=True): ''' Load the cube in and derive the property arrays. ''' if add_noise: if rms_noise is None: raise TypeError("Must specify value of rms noise.") cube, hdr = getdata(filename, header=True) # Optionally scale noise by 1/10th of the 98th percentile in the cube if rms_noise == 'scaled': rms_noise = 0.1 * np.percentile(cube[np.isfinite(cube)], 98) from scipy.stats import norm if not slicewise_noise: cube += norm.rvs(0.0, rms_noise, cube.shape) else: spec_shape = cube.shape[0] slice_shape = cube.shape[1:] for i in range(spec_shape): cube[i, :, :] += norm.rvs(0.0, rms_noise, slice_shape) sc = SpectralCube(data=cube, wcs=WCS(hdr)) mask = LazyMask(np.isfinite, sc) sc = sc.with_mask(mask) else: sc = filename reduc = Mask_and_Moments(sc, scale=rms_noise) reduc.make_mask(mask=reduc.cube > nsig * reduc.scale) reduc.make_moments() reduc.make_moment_errors() return reduc.to_dict()
def load_and_reduce(filename, add_noise=False, rms_noise=0.001, nsig=3, slicewise_noise=True): ''' Load the cube in and derive the property arrays. ''' if add_noise: if rms_noise is None: raise TypeError("Must specify value of rms noise.") cube, hdr = getdata(filename, header=True) # Optionally scale noise by 1/10th of the 98th percentile in the cube if rms_noise == 'scaled': rms_noise = 0.1*np.percentile(cube[np.isfinite(cube)], 98) from scipy.stats import norm if not slicewise_noise: cube += norm.rvs(0.0, rms_noise, cube.shape) else: spec_shape = cube.shape[0] slice_shape = cube.shape[1:] for i in range(spec_shape): cube[i, :, :] += norm.rvs(0.0, rms_noise, slice_shape) sc = SpectralCube(data=cube, wcs=WCS(hdr)) mask = LazyMask(np.isfinite, sc) sc = sc.with_mask(mask) else: sc = filename reduc = Mask_and_Moments(sc, scale=rms_noise) reduc.make_mask(mask=reduc.cube > nsig * reduc.scale) reduc.make_moments() reduc.make_moment_errors() return reduc.to_dict()
def _spectrum_from_component(self, layer, component, wcs, mask=None): data = SpectralCube(component.data, wcs) if mask is not None: data = data.with_mask(mask) spec_data = data.sum((1, 2)) spec_data = Spectrum1DRef(spec_data.data, unit=spec_data.unit, dispersion=data.spectral_axis.data, dispersion_unit=data.spectral_axis.unit, wcs=data.wcs) # Store the relation between the component and the specviz data. If # the data exists, first remove the component from specviz and then # re-add it. if layer in self._specviz_data_cache: old_spec_data = self._specviz_data_cache[layer] dispatch.on_remove_data.emit(old_spec_data) self._specviz_data_cache[layer] = spec_data dispatch.on_add_to_window.emit(spec_data)
def calc_structure_fcn(catalog, bootiter=0,doPlot=False): cat = catalog if 'sf_offset' not in cat.keys(): keylist = ['sf_offset','sf_index','sf_ngood', 'sf_index_err','sf_offset_err', 'vca_index', 'vca_index_err'] for thiskey in keylist: c = Column(np.zeros(len(cat))+np.nan,name=thiskey) cat.add_column(c) current_open_file = '' for cloud in cat: root = cloud['orig_file'].split('_') orig_file = 'COHRS_{0}_{1}.fits'.format(root[-2], root[-1]) asgn_file = cloud['orig_file'] + '_fasgn.fits' if os.path.isfile(datadir+'COHRS_tiles/'+orig_file): if current_open_file != datadir+'COHRS_tiles/'+orig_file: hdu = fits.open(datadir+'COHRS_tiles/'+orig_file,memmap=False) cat.write('cohrs_structurefunc.fits',overwrite=True) w = wcs.WCS(hdu[0].header) hdr2 = w.to_header() hdr2['BMAJ'] = 15./3600 hdr2['BMIN'] = 15./3600 hdr2['BPA'] = 0. co = SpectralCube(hdu[0].data,w,header=hdr2) hdu = fits.open(datadir+'ASGN/'+asgn_file,memmap=False) w = wcs.WCS(hdu[0].header) hdr2 = w.to_header() hdr2['BMAJ'] = 15./3600 hdr2['BMIN'] = 15./3600 hdr2['BPA'] = 0. asgn = SpectralCube(hdu[0].data,w,header=hdr2) # masked_co = co.with_mask(asgn>0*u.dimensionless_unscaled) # moment = masked_co.moment(0) current_open_file = datadir+'COHRS_tiles/'+orig_file print(cloud['cloud_id']) mask = (asgn == cloud['cloud_id']*u.dimensionless_unscaled) subcube = co.with_mask(mask) subcube = subcube.subcube_from_mask(mask) # subcube.moment0().quicklook() # plt.show() if subcube.shape[0] > 10: # zeros = np.zeros_like(subcube) # np.random.randn(*subcube.shape)*0.5 # concatdata = np.vstack([subcube.filled_data[:],zeros]) # hdr2 = subcube.wcs.to_header() # hdr2['BMAJ'] = 15./3600 # hdr2['BMIN'] = 15./3600 # hdr2['BPA'] = 0. # newcube = SpectralCube(concatdata,subcube.wcs,header=hdr2) # if True: try: pcaobj = pca.PCA(subcube, distance=cloud['bgps_distance_pc']*u.pc) vcaobj = vca.VCA(subcube, distance=cloud['bgps_distance_pc']*u.pc) vcaobj.run(verbose=False, high_cut = 0.3/u.pix) pcaobj.run(verbose=True,mean_sub=True, min_eigval=0.9,eigen_cut_method='proportion') cloud['sf_index']= pcaobj.index cloud['sf_offset'] = pcaobj.intercept.value cloud['sf_ngood'] = np.min([np.isfinite(pcaobj.spatial_width).sum(), np.isfinite(pcaobj.spectral_width).sum()]) cloud['sf_index_err'] = (pcaobj.index_error_range[1]-pcaobj.index_error_range[0])*0.5 cloud['sf_offset_err'] = ((pcaobj.intercept_error_range[1]-pcaobj.intercept_error_range[0])*0.5).value cloud['vca_index'] = vcaobj.slope cloud['vca_index_err'] = vcaobj.slope_err print('{0} +/- {1}'.format(cloud['sf_index'], cloud['sf_index_err']), cloud['sf_offset']) # import pdb; pdb.set_trace() # else: except: pass cat.write('output_catalog2.fits',overwrite=True)
# 88.63185 GHz (0.48257208, 0.0) # 88.63394 GHz (0.3509686, 0.0) # 88.6316024 GHz (0.49761587, 0.0) from FITS_tools import regrid_cube hnc_regrid = regrid_cube(cubehnc.filled_data[:], cubehnc.header, cubehcn.header) cubehnc = SpectralCube(data=hnc_regrid, wcs=cubehcn.wcs) #cubehnc._wcs = cubehcn.wcs #cubehnc.mask._wcs = cubehcn.wcs mask = (cubehcn > 0.5) mask2 = (cubehcn > 0.5) #mask2._wcs = cubehnc.wcs hcn_flat = cubehcn.with_mask(mask).flattened() hnc_flat = cubehnc.with_mask(mask2).flattened() mask3 = cubehnc > 0.5 mask4 = cubehnc > 0.5 #mask4._wcs = cubehcn.wcs hnc_flat2 = cubehnc.with_mask(mask3).flattened() hcn_flat2 = cubehcn.with_mask(mask4).flattened() import pylab as pl pl.clf() pl.plot(hnc_flat, hcn_flat, ',', alpha=0.5) pl.plot(hnc_flat2, hcn_flat2, ',', alpha=0.5) pl.plot([0,5],[0,5],'k--') pl.axis([0,5,0,5]) dd = cubehcn.to_ds9()
dataset1 = np.load(path1) cube1 = np.empty((500, 32, 32)) count = 0 for posn, kept in zip(*dataset1["channels"]): posn = int(posn) if kept: cube1[posn, :, :] = dataset1["cube"][count, :, :] count += 1 else: cube1[posn, :, :] = ra.normal(0.005, 0.005, (32, 32)) sc1 = SpectralCube(data=cube1, wcs=WCS(header)) mask = LazyMask(np.isfinite, sc1) sc1 = sc1.with_mask(mask) # Set the scale for the purposes of the tests props1 = Moments(sc1, scale=0.003031065017916262 * u.Unit("")) # props1.make_mask(mask=mask) props1.make_moments() props1.make_moment_errors() dataset1 = props1.to_dict() moment0_hdu1 = fits.PrimaryHDU(dataset1["moment0"][0], header=dataset1["moment0"][1]) moment0_proj = Projection.from_hdu(moment0_hdu1) ##############################################################################
denscube = denscube.with_mask(okmask) colcube = SpectralCube.read(paths.dpath("H2CO_ParameterFits_{0}col.fits".format(meastype))) colcube = colcube.with_mask(okmask) goodmask_std = stdcube < 0.5 flathead = denscube.wcs.dropaxis(2).to_header() denscube_lin = SpectralCube(10**denscube.filled_data[:].value, wcs=denscube.wcs, mask=okmask) colcube_lin = SpectralCube(10**colcube.filled_data[:].value, wcs=denscube.wcs, mask=okmask) totalcol = colcube_lin.sum(axis=0) totalcolgood = colcube_lin.with_mask(goodmask).sum(axis=0) totalcolgoodstd = colcube_lin.with_mask(goodmask_std).sum(axis=0) denscol = SpectralCube(denscube_lin.filled_data[:] * colcube_lin.filled_data[:], wcs=denscube.wcs, mask=okmask) wtdmeandens = np.log10(denscol.sum(axis=0) / totalcol) mindens_std = denscube.with_mask(goodmask_std).min(axis=0) mindens_chi2 = denscube.with_mask(goodmask).min(axis=0) hdu1 = fits.PrimaryHDU(data=wtdmeandens.value, header=flathead) hdu1.writeto(paths.dpath("H2CO_ParameterFits_weighted_mean_{0}_density.fits".format(meastype)), clobber=True) masked_wtdmeans = np.log10(denscol.with_mask(goodmask).sum(axis=0) / totalcolgood) hdu2 = fits.PrimaryHDU(data=masked_wtdmeans.value,
def calc_irlum(catalog = 'cohrs_finalcatalog_clumpflux_medaxis.fits', refresh=False): ctrr = 0 cat = Table.read(catalog) current_open_file = '' if 'ir_luminosity' not in cat.keys(): keylist = ['ir_luminosity','ir_flux','ir_flux_short', 'ir_lum_short','bg_flux','bg_lum'] for thiskey in keylist: c = Column(np.zeros(len(cat))+np.nan,name=thiskey) cat.add_column(c) for cloud in cat: if np.isnan(cloud['ir_luminosity']) or refresh: orig_file = cloud['orig_file']+'.fits' asgn_file = cloud['orig_file']+'_fasgn.fits' higal_file = orig_file.replace('cohrs','higal_xmatch') if os.path.isfile(datadir+'COHRS/'+orig_file) and \ os.path.isfile(datadir+'HIGAL_MATCHED/'+higal_file): if current_open_file != datadir+'COHRS/'+orig_file: hdu = fits.open(datadir+'COHRS/'+orig_file,memmap=False) w = wcs.WCS(hdu[0].header) hdr2 = w.to_header() hdr2['BMAJ'] = 15./3600 hdr2['BMIN'] = 15./3600 hdr2['BPA'] = 0. co = SpectralCube(hdu[0].data,w,header=hdr2) irfull= fits.open(datadir+'HIGAL_MATCHED/'+higal_file,memmap=False) irlong = fits.open(datadir+'HIGAL_MATCHED2/'+higal_file,memmap=False) irmap = (irfull[0].data-irlong[0].data) irmap2 = irfull[0].data asgn = fits.getdata(datadir+'ASSIGNMENTS/'+asgn_file,memmap=False) masked_co = co.with_mask(asgn>0*u.dimensionless_unscaled) moment = masked_co.moment(0) current_open_file = datadir+'COHRS/'+orig_file cat.write('output_catalog.fits',overwrite=True) # mask = np.zeros(co.shape,dtype=np.bool) # mask[asgn == cloud['cloud_id']]=True cloud_cube = co.with_mask(asgn == cloud['cloud_id']) cloud_moment = cloud_cube.moment(0) cloud_cube = 0.0 fraction = (cloud_moment.value/moment.value) planemask = skm.binary_closing(fraction > 0,selem=skm.disk(3)) fraction = np.nanmean(fraction) rind = (skm.binary_dilation(planemask,selem=skm.disk(6)) ^\ skm.binary_dilation(planemask,selem=skm.disk(3)))*\ np.isfinite(irmap2) if np.any(rind): rindvals = irmap2[rind] clipval = 4*np.percentile(rindvals,15.87)-\ 3*(np.percentile(rindvals,2.28)) rind *= irmap2 <= clipval yv,xv = np.where(rind) x0,y0 = np.median(xv),np.median(yv) dataz = np.c_[np.ones(xv.size), xv-x0, yv-y0] try: lsqcoeffs,_,_,_ = np.linalg.lstsq(dataz,irmap2[rind]) outputs = lsq(myplane,np.r_[lsqcoeffs,0], args=(xv-x0, yv-y0, irmap2[rind]), loss = 'soft_l1') coeffs = outputs.x yhit,xhit = np.where(planemask) bg = coeffs[0]+coeffs[1]*(xhit-x0)+\ coeffs[2]*(yhit-y0)+coeffs[3]*(yhit-y0)*(xhit-x0) # I am sitcking a 6e11 in here as the frequency of # the 500 microns bgavg = np.sum(fraction*bg)/6e11 bglum = bgavg*cloud['distance']**2*\ 3.086e18**2*np.pi*4/3.84e33 except ValueError: import pdb; pdb.set_trace() ir_flux = np.nansum(fraction*(irmap[planemask]))/6e11 ir_lum = ir_flux * cloud['distance']**2*\ 3.086e18**2*np.pi*4/3.84e33 ir_flux2 = np.nansum(fraction*irmap2[planemask])/6e11 ir_lum2 = ir_flux2 * cloud['distance']**2*\ 3.086e18**2*np.pi*4/3.84e33 cloud['ir_flux'] = ir_flux2 cloud['ir_luminosity'] = ir_lum2 cloud['ir_flux_short'] = ir_flux cloud['ir_lum_short'] = ir_lum cloud['bg_flux'] = bgavg cloud['bg_lum'] = bglum print(cloud['cloud_id'],ir_flux,ir_lum,ir_lum2,bglum) cat.write('output_catalog.fits',overwrite=True) ctrr+=1 if ctrr==20: return(cat) # if cloud['volume_pc2_kms']>1e2: # import pdb; pdb.set_trace() return(cat)
def smooth_cube( incube=None, outfile=None, angular_resolution=None, linear_resolution=None, distance=None, velocity_resolution=None, nan_treatment='interpolate', # can also be 'fill' tol=None, make_coverage_cube=False, collapse_coverage=False, coveragefile=None, coverage2dfile=None, dtype=np.float32, overwrite=True ): """ Smooth an input cube to coarser angular or spectral resolution. This lightly wraps spectral cube and some of the error checking is left to that. tol is a fraction. When the target beam is within tol of the original beam, we just copy. Optionally, also calculate a coverage footprint in which original (finite) cube coverage starts at 1.0 and the output cube shows the fraction of finite pixels. """ # &%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&% # Error checking # &%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&% # Require a valid cube or map input if type(incube) is SpectralCube: cube = incube elif type(incube) == type("hello"): cube = SpectralCube.read(incube) else: logger.error("Input must be a SpectralCube object or a filename.") # Allow huge operations. If the speed or segfaults become a huge # problem, we will adjust our strategy here. cube.allow_huge_operations = True # Check that only one target scale is set if (angular_resolution is not None) and (linear_resolution is not None): logger.error('Only one of angular_resolution or ', 'linear_resolution can be set') return(None) # Work out the target angular resolution if angular_resolution is not None: if type(angular_resolution) is str: angular_resolution = u.Quantity(angular_resolution) if linear_resolution is not None: if distance is None: logger.error('Convolution to linear resolution requires a distance.') return(None) if type(distance) is str: distance = u.Quantity(distance) if type(linear_resolution) is str: linear_resolution = u.Quantity(linear_resolution) angular_resolution = (linear_resolution / distance * u.rad).to(u.arcsec) dist_mpc_val = float(distance.to(u.pc).value) / 1e6 cube._header.append(('DIST_MPC',dist_mpc_val,'Used in convolution')) if tol is None: tol = 0.0 # &%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&% # Convolution to coarser beam # &%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&% if angular_resolution is not None: logger.info("... convolving from beam: "+str(cube.beam)) target_beam = Beam(major=angular_resolution, minor=angular_resolution, pa=0 * u.deg) logger.info("... convolving to beam: "+str(target_beam)) new_major = float(target_beam.major.to(u.arcsec).value) old_major = float(cube.beam.major.to(u.arcsec).value) delta = (new_major-old_major)/old_major logger.info("... fractional change: "+str(delta)) if make_coverage_cube: coverage = SpectralCube(np.isfinite(cube.unmasked_data[:])*1.0, wcs=cube.wcs, header=cube.header, meta={'BUNIT': ' ', 'BTYPE': 'Coverage'}) coverage = coverage.with_mask(LazyMask(np.isfinite,cube=coverage)) # Allow huge operations. If the speed or segfaults become a huge # problem, we will adjust our strategy here. coverage.allow_huge_operations = True if delta > tol: logger.info("... proceeding with convolution.") cube = cube.convolve_to(target_beam, nan_treatment=nan_treatment) if make_coverage_cube: coverage = coverage.convolve_to(target_beam, nan_treatment=nan_treatment) if np.abs(delta) < tol: logger.info("... current resolution meets tolerance.") if delta < -1.0*tol: logger.info("... resolution cannot be matched. Returning") return(None) # &%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&% # Spectral convolution # &%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&% # This is only a boxcar smooth right now and does not downsample # or update the header. if velocity_resolution is not None: if type(velocity_resolution) is str: velocity_resolution = u.Quantity(velocity_resolution) dv = scdr.channel_width(cube) nChan = (velocity_resolution / dv).to(u.dimensionless_unscaled).value if nChan > 1: cube = cube.spectral_smooth(Box1DKernel(nChan)) if make_coverage_cube: coverage = coverage.spectral_smooth(Box1DKernel(nChan)) # &%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&% # Write or return as requested # &%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&%&% if outfile is not None: # cube.write(outfile, overwrite=overwrite) hdu = fits.PrimaryHDU(np.array(cube.filled_data[:], dtype=dtype), header=cube.header) hdu.writeto(outfile, overwrite=overwrite) if make_coverage_cube: if coveragefile is not None: hdu = fits.PrimaryHDU(np.array(coverage.filled_data[:], dtype=dtype), header=coverage.header) hdu.writeto(coveragefile, overwrite=overwrite) if collapse_coverage: if coveragefile and not coverage2dfile: coverage2dfile = coveragefile.replace('.fits','2d.fits') coverage_collapser(coverage, coverage2dfile=coverage2dfile, overwrite=overwrite) # coverage.write(coveragefile, overwrite=overwrite) return(cube)
def common_cube(filename, target_rms=None, target_resolution=None, datadir='', outdir='', outname='common.fits', cube=None, rmsname=None, rmsmap=None, distance=None, overwrite=True, return_cube=False, huge=True): """ Convolves and adds noise to a data cube to arrive at a target linear resolution and noise level Parameters: filename : str File name of spectral data cube to process outname : str File name for output cube target_rms : astropy.Quantity Target RMS level in units of cube brightness target_resolution : astropy.Quantity Target resolution expressed as either length (linear resolution) or angle (angular resolution) datadir : str Directory for input data outdir : str Directory for output data rmsname : str Name for input RMS data cube rmsmap : np.ndarray numpy array of noise values at positions corresponding to the spectral cube. distance : astropy.Quantity Distance to target; required if a linear target resolution is requested overwrite : bool Overwrite output products if they already exist? return_cube : bool Return a SpectralCube? """ if cube is None: cube = SpectralCube.read(os.path.join(datadir, filename)) cube.allow_huge_operations = huge orig_beam_area = cube.beam.sr target_beam = None if target_resolution is not None: if target_resolution.unit.is_equivalent(u.pc): if distance is None: warnings.warn( "A distance with units must be provided to reach a target linear resolution" ) raise ValueError target_beam_size = (target_resolution / distance).to( u.dimensionless_unscaled) * u.rad elif target_resolution.is_equivalent(u.rad): target_beam_size = target_resolution else: warnings.warn( "target_resolution must be either linear distance or angle") raise ValueError target_beam = Beam(major=target_beam_size, minor=target_beam_size, pa=0 * u.deg) if target_beam > cube.beam: cube = cube.convolve_to(target_beam) else: warnings.warn('Target linear resolution unreachable.') if target_rms is not None: if target_beam is None: target_beam = cube.beam noisevals = np.random.randn(*cube.shape) null_beam = Beam(major=1e-7 * u.deg, minor=1e-7 * u.deg, pa=0 * u.deg) noisevals[~np.isfinite(cube)] = np.nan noisecube = SpectralCube(noisevals, cube.wcs, header=cube.header, beam=null_beam, meta={'BUNIT': 'K'}) noisecube = noisecube.with_mask(np.isfinite(cube)) noisecube.allow_huge_operations = huge area_ratio = (orig_beam_area / target_beam.sr).to( u.dimensionless_unscaled).value noisecube = noisecube.convolve_to(target_beam) if (rmsname is not None) and (rmsmap is None): rmsmap = fits.getdata(os.path.join(datadir, rmsname)) * u.K if rmsmap is None: warnings.warn( "One of rmsmap or rmsname must be provided for noise homogenization" ) raise FileNotFoundError rmsamplitude = rmsmap * area_ratio**0.5 if np.all(rmsamplitude > target_rms): warnings.warn("All noise values larger than target value") else: addamplitude = (target_rms**2 - rmsamplitude**2) addamplitude[addamplitude < 0] = 0.0 addamplitude.shape = addamplitude.shape noisevals = noisecube.filled_data[:] noisevals /= np.nanstd(noisevals) noisevals *= (addamplitude**0.5) cube.allow_huge_operations = huge cube += noisevals if type(outname) is str: cube.write(outdir + outname, overwrite=overwrite) if return_cube: return (cube) else: return (True)
class Data3D(Data): """ Creates a data cube structure. Attributes: address: file name. data: the data cube. """ def __init__(self, address): """Defines a new data cube object. Parameters: address (str): file name. """ super(Data3D, self).__init__(address) self.logger = get_logger(__name__) def load(self): """Load the data cube""" try: self.data = SpectralCube.read(self.address) except: self.logger.warn('Trying to fix the cube') cube = fits.open(self.address)[0] cube.header['CUNIT3'] = 'm/s' cube.header['CRVAL3'] = cube.header['CRVAL3'] * 1.E3 cube.header['CDELT3'] = cube.header['CDELT3'] * 1.E3 self.data = SpectralCube(cube.data, WCS(cube.header)) self.logger.info('Cube fixed') def save(self, filename=None, overwrite=True): """Save the data cube""" self.data.write(filename or self.address, overwrite=overwrite) @property def wcs(self): """Return the WCS with the position data.""" return self.data.wcs.sub(['longitude', 'latitude']) def get_coord(self, xpix, ypix, frame='fk5'): """Return the (ra, dec) coordinates of the input pixel location. Parameters: xpix (float): x-position of the coordinate. ypix (float): y-position of the coordinate. frame (str, default=fk5): sky frame projection. Returns: coord (astropy.SkyCoord): sky coordinate of the input location. Note: xpix and ypix are zero based. """ ra, dec = self.wcs.all_pix2world([[xpix, ypix]], 0)[0] return SkyCoord(ra=ra * u.degree, dec=dec * u.degree, frame=frame) def get_pixel(self, coord): crd = [[coord.ra.degree, coord.dec.degree]] return self.wcs.all_world2pix(crd, 0)[0] #return self.wcs.world_to_pixel(coord) def get_spectrum(self, coord=None, pixel=None): if coord is not None: xy = self.get_pixel(coord) elif pixel is not None: xy = pixel else: raise ValueError('Could not determine position') x, y = map(int, xy) self.logger.info('Extracting spectrum at pixel: %i, %i', x, y) return self.data[:, y, x] def get_avg_spectrum(self, coord, r=None): # Position xy = self.get_pixel(coord) x, y = map(int, xy) self.logger.info('Region centered at pixel: %i, %i', x, y) # Multiple beams bmaj = 0. bmin = 0. for beam in self.data.beams: bmaj += beam.major.to(u.deg).value bmin += beam.minor.to(u.deg).value bmaj = bmaj / len(self.data.beams) bmin = bmin / len(self.data.beams) # Get mask mask = image_circular_mask(self.data, xy=[x, y], r=r, bmin=bmin, bmaj=bmaj) # Get spectrum maskedcube = self.data.with_mask(mask) return maskedcube.mean(axis=(-2, -1)) def rotate(self, angle, source, centre=(0, 0), mode='bilinear', **kwargs): """Rotate the cube. Parameters angle: angle of rotation in degrees. centre: centre of rotation. mode: interpolation mode. """ #old_centre = self.centre # Rotate the cube aux = None for j, slc in enumerate(self.data.unmasked_data[:]): rotated = rotate(slc, angle, centre=centre, mode=mode) if aux is None: aux = np.array([rotated]) else: aux = np.append(aux, [rotated], axis=0) # Create a new fits file hdu = fits.PrimaryHDU(aux) hdu.header = self.data.header hdu.header['COMMENT'] = 'Rotated %.3f deg, center %i, %i' % \ ((angle,)+centre) self.logger.info('Image rotated %.1f deg, center %i, %i', angle, *centre) # Redefine the reference pixel hdu.header['CRPIX1'] = aux.shape[2] / 2. + .5 hdu.header['CRPIX2'] = aux.shape[1] / 2. + .5 hdu.header['CRVAL1'] = source.position.ra.to(u.deg).value hdu.header['CRVAL2'] = source.position.dec.to(u.deg).value # Redifine header rotation #if 'CROTA2' in hdu.header: # #if hdu.header['CROTA2']==angle: # self.logger.info('Deleting rotation keywords from header') try: del hdu.header['CROTA2'] del hdu.header['CROTA1'] except KeyError: pass #else: # self.logger.info('Changing rotation keywords from header') # hdu.header['CROTA2'] = hdu.header['CROTA2']-angle #else: # self.logger.info('Setting rotation header keywords') # hdu.header['CROTA1'] = 0 # hdu.header['CROTA2'] = angle return hdu
add_noise = sys.argv[3] if add_noise == "True" or add_noise == "T": add_noise = True else: add_noise = False data1, hdr1 = fits.getdata(fits1, header=True) data2, hdr2 = fits.getdata(fits2, header=True) if add_noise: data1 += np.random.normal(0.0, 0.788 / 10, data1.shape) data2 += np.random.normal(0.0, 0.788 / 10, data2.shape) cube1 = SpectralCube(data=data1, wcs=WCS(hdr1)) cube1 = cube1.with_mask(LazyMask(np.isfinite, cube1)) cube2 = SpectralCube(data=data2, wcs=WCS(hdr2)) cube2 = cube2.with_mask(LazyMask(np.isfinite, cube2)) set1 = Mask_and_Moments(cube1) mask = cube1 > 3*set1.scale set1.make_mask(mask=mask) set1.make_moments() set1.make_moment_errors() dataset1 = set1.to_dict() set2 = Mask_and_Moments(cube2) mask = cube2 > 3*set2.scale set2.make_mask(mask=mask) set2.make_moments() set2.make_moment_errors()
for thisfile in fl: fig, [[ax1, ax2], [ax3, ax4]] = plt.subplots(2, 2, constrained_layout=True) fig.set_size_inches(6.5, 6.5) cube = SpectralCube.read(thisfile) gal = os.path.split(thisfile)[-1].split('_')[0] shortfile = os.path.split(thisfile)[-1] try: mask = SpectralCube.read(degas_data + '/masks/{0}_mask.fits'.format(gal)) mask = mask.with_spectral_unit(u.km / u.s, velocity_convention='radio') hdr = mask.header hdr['CTYPE3'] = 'VRAD' mask = SpectralCube(mask.filled_data[:], wcs.WCS(hdr), header=hdr) mask = mask.with_mask(mask.filled_data[:] > 0) mask = mask.spectral_interpolate(cube.spectral_axis) mask = mask.reproject(cube.header) except FileNotFoundError: print('No mask for ' + thisfile) mask = SpectralCube(np.ones(cube.shape), wcs=cube.wcs, header=cube.header) rmsamplitude = scm.noise_cube(cube.filled_data[:].value, box=5, spec_box=5, iterations=5, bandpass_smooth_window=21) s2n = cube.filled_data[:].value / rmsamplitude
np.save( hi_stackpath("radial_stacking_pixelsinbin_{0}_noCO.npy").format(wstring), num_pixels) np.save( hi_stackpath("radial_stacking_pixelsinbin_north_{0}_noCO.npy").format( wstring), num_pixels_n) np.save( hi_stackpath("radial_stacking_pixelsinbin_south_{0}_noCO.npy").format( wstring), num_pixels_s) spec_shape = hi_cube_peakvel.shape[0] peakvel_stack = SpectralCube(data=total_spectrum_hi_radial_peakvel.T.reshape( (spec_shape, bin_centers.size, 1)), wcs=hi_cube_peakvel.wcs) peakvel_stack = peakvel_stack.with_mask( np.ones_like(peakvel_stack, dtype='bool')) peakvel_stack.write(hi_stackpath( "peakvel_stacked_radial_{0}_noCO.fits".format(wstring)), overwrite=True) peakvel_stack_n = SpectralCube( data=total_spectrum_hi_radial_peakvel_n.T.reshape( (spec_shape, bin_centers.size, 1)), wcs=hi_cube_peakvel.wcs) peakvel_stack_n = peakvel_stack_n.with_mask( np.ones_like(peakvel_stack_n, dtype='bool')) peakvel_stack_n.write(hi_stackpath( "peakvel_stacked_radial_north_{0}_noCO.fits".format(wstring)), overwrite=True) peakvel_stack_s = SpectralCube( data=total_spectrum_hi_radial_peakvel_s.T.reshape(
def calc_structure_fcn(catalog, bootiter=0, doPlot=False): cat = catalog if 'sf_offset' not in cat.keys(): keylist = [ 'sf_offset', 'sf_index', 'sf_ngood', 'sf_index_err', 'sf_offset_err', 'vca_index', 'vca_index_err' ] for thiskey in keylist: c = Column(np.zeros(len(cat)) + np.nan, name=thiskey) cat.add_column(c) current_open_file = '' for cloud in cat: root = cloud['orig_file'].split('_') orig_file = 'COHRS_{0}_{1}.fits'.format(root[-2], root[-1]) asgn_file = cloud['orig_file'] + '_fasgn.fits' if os.path.isfile(datadir + 'COHRS_tiles/' + orig_file): if current_open_file != datadir + 'COHRS_tiles/' + orig_file: hdu = fits.open(datadir + 'COHRS_tiles/' + orig_file, memmap=False) cat.write('cohrs_structurefunc.fits', overwrite=True) w = wcs.WCS(hdu[0].header) hdr2 = w.to_header() hdr2['BMAJ'] = 15. / 3600 hdr2['BMIN'] = 15. / 3600 hdr2['BPA'] = 0. co = SpectralCube(hdu[0].data, w, header=hdr2) hdu = fits.open(datadir + 'ASGN/' + asgn_file, memmap=False) w = wcs.WCS(hdu[0].header) hdr2 = w.to_header() hdr2['BMAJ'] = 15. / 3600 hdr2['BMIN'] = 15. / 3600 hdr2['BPA'] = 0. asgn = SpectralCube(hdu[0].data, w, header=hdr2) # masked_co = co.with_mask(asgn>0*u.dimensionless_unscaled) # moment = masked_co.moment(0) current_open_file = datadir + 'COHRS_tiles/' + orig_file print(cloud['cloud_id']) mask = (asgn == cloud['cloud_id'] * u.dimensionless_unscaled) subcube = co.with_mask(mask) subcube = subcube.subcube_from_mask(mask) # subcube.moment0().quicklook() # plt.show() if subcube.shape[0] > 10: # zeros = np.zeros_like(subcube) # np.random.randn(*subcube.shape)*0.5 # concatdata = np.vstack([subcube.filled_data[:],zeros]) # hdr2 = subcube.wcs.to_header() # hdr2['BMAJ'] = 15./3600 # hdr2['BMIN'] = 15./3600 # hdr2['BPA'] = 0. # newcube = SpectralCube(concatdata,subcube.wcs,header=hdr2) # if True: try: pcaobj = pca.PCA(subcube, distance=cloud['bgps_distance_pc'] * u.pc) vcaobj = vca.VCA(subcube, distance=cloud['bgps_distance_pc'] * u.pc) vcaobj.run(verbose=False, high_cut=0.3 / u.pix) pcaobj.run(verbose=True, mean_sub=True, min_eigval=0.9, eigen_cut_method='proportion') cloud['sf_index'] = pcaobj.index cloud['sf_offset'] = pcaobj.intercept.value cloud['sf_ngood'] = np.min([ np.isfinite(pcaobj.spatial_width).sum(), np.isfinite(pcaobj.spectral_width).sum() ]) cloud['sf_index_err'] = (pcaobj.index_error_range[1] - pcaobj.index_error_range[0]) * 0.5 cloud['sf_offset_err'] = ( (pcaobj.intercept_error_range[1] - pcaobj.intercept_error_range[0]) * 0.5).value cloud['vca_index'] = vcaobj.slope cloud['vca_index_err'] = vcaobj.slope_err print( '{0} +/- {1}'.format(cloud['sf_index'], cloud['sf_index_err']), cloud['sf_offset']) # import pdb; pdb.set_trace() # else: except: pass cat.write('output_catalog2.fits', overwrite=True)
def reduce_and_save(filename, add_noise=False, regrid_linewidth=False, rms_noise=0.001 * u.K, output_path="", cube_output=None, nsig=3, slicewise_noise=True): ''' Load the cube in and derive the property arrays. ''' if add_noise or regrid_linewidth: sc = SpectralCube.read(filename) if add_noise: if rms_noise is None: raise TypeError("Must specify value of rms noise.") cube = sc.filled_data[:].value # Optionally scale noise by 1/10th of the 98th percentile in the # cube if rms_noise == 'scaled': rms_noise = 0.1 * \ np.percentile(cube[np.isfinite(cube)], 98) * sc.unit from scipy.stats import norm if not slicewise_noise: cube += norm.rvs(0.0, rms_noise.value, cube.shape) else: spec_shape = cube.shape[0] slice_shape = cube.shape[1:] for i in range(spec_shape): cube[i, :, :] += norm.rvs(0.0, rms_noise.value, slice_shape) sc = SpectralCube(data=cube * sc.unit, wcs=sc.wcs, meta={"BUNIT": "K"}) mask = LazyMask(np.isfinite, sc) sc = sc.with_mask(mask) if regrid_linewidth: # Normalize the cubes to have the same linewidth # channels_per_sigma=20 scales to the largest mean line width in # SimSuite8 (~800 km/s; Design 22). So effectively everything is # "smoothed" to have this line width # Intensities are normalized by their 95% value. sc = preprocessor(sc, min_intensity=nsig * rms_noise, norm_intensity=True, norm_percentile=95, channels_per_sigma=20) else: sc = filename # Run the same signal masking procedure that was used for the # COMPLETE cubes if add_noise: # The default settings were set based on these cubes sc = make_signal_mask(sc)[0] reduc = Mask_and_Moments(sc, scale=rms_noise) if not add_noise: reduc.make_mask(mask=reduc.cube > nsig * reduc.scale) reduc.make_moments() reduc.make_moment_errors() # Remove .fits from filename save_name = os.path.splitext(os.path.basename(filename))[0] reduc.to_fits(os.path.join(output_path, save_name)) # Save the noisy cube too if add_noise or regrid_linewidth: save_name += ".fits" if cube_output is None: sc.hdu.writeto(os.path.join(output_path, save_name)) else: sc.hdu.writeto(os.path.join(cube_output, save_name))
def calc_noise_in_cube(cube, masking_scheme='simple', mask=None, spatial_average_npix=None, spatial_average_nbeam=5.0, spectral_average_nchan=5, verbose=False): """ Estimate rms noise in a (continuum-subtracted) spectral cube. Parameters ---------- cube : SpectralCube object Input spectral cube (needs to be continuum-subtracted) masking_scheme : {'simple', 'user'}, optional Scheme for flagging signal in the cube. 'simple' means to flag all values above 3*rms or below -3*rms (default scheme); 'user' means to use the user-specified mask (i.e., `mask`). mask : `np.ndarray` object, optional User-specified signal mask (this parameter is ignored if `masking_scheme` is not 'user') spatial_average_npix : int, optional Size of the spatial averaging box, in terms of pixel number If not None, `spatial_average_nbeam` will be ingored. (Default: None) spatial_average_nbeam : float, optional Size of the spatial averaging box, in the unit of beam FWHM (Default: 5.0) spectral_average_nchan : int, optional Size of the spectral averaging box, in terms of channel number (Default: 5) verbose : bool, optional Whether to print the detailed processing information in terminal Default is to not print. Returns ------- rmscube : SpectralCube object Spectral cube containing the rms noise at each ppv location """ from scipy.ndimage import generic_filter from astropy.stats import mad_std if masking_scheme not in ['simple', 'user']: raise ValueError("'masking_scheme' should be specified as" "either 'simple' or 'user'") elif masking_scheme == 'user' and mask is None: raise ValueError("'masking_scheme' set to 'user', yet " "no user-specified mask found") # extract negative values (only needed if masking_scheme='simple') if masking_scheme == 'simple': if verbose: print("Extracting negative values...") negmask = cube < (0 * cube.unit) negdata = cube.with_mask(negmask).filled_data[:].value negdata = np.stack([negdata, -1 * negdata], axis=-1) else: negdata = None # find rms noise as a function of channel if verbose: print("Estimating rms noise as a function of channel...") if masking_scheme == 'user': mask_v = mask elif masking_scheme == 'simple': rms_v = mad_std(negdata, axis=(1, 2, 3), ignore_nan=True) uplim_v = (3 * rms_v * cube.unit).reshape(-1, 1, 1) lolim_v = (-3 * rms_v * cube.unit).reshape(-1, 1, 1) mask_v = (((cube - uplim_v) < (0 * cube.unit)) & ((cube - lolim_v) > (0 * cube.unit))) rms_v = cube.with_mask(mask_v).mad_std(axis=(1, 2)).quantity.value rms_v = generic_filter(rms_v, np.nanmedian, mode='constant', cval=np.nan, size=spectral_average_nchan) # find rms noise as a function of sightline if verbose: print("Estimating rms noise as a function of sightline...") if masking_scheme == 'user': mask_s = mask elif masking_scheme == 'simple': rms_s = mad_std(negdata, axis=(0, 3), ignore_nan=True) uplim_s = 3 * rms_s * cube.unit lolim_s = -3 * rms_s * cube.unit mask_s = (((cube - uplim_s) < (0 * cube.unit)) & ((cube - lolim_s) > (0 * cube.unit))) rms_s = cube.with_mask(mask_s).mad_std(axis=0).quantity.value if spatial_average_npix is None: beamFWHM_pix = (cube.beam.major.to(u.deg).value / np.abs(cube.wcs.celestial.wcs.cdelt.min())) beamFWHM_pix = np.max([beamFWHM_pix, 3.]) spatial_average_npix = int(spatial_average_nbeam * beamFWHM_pix) rms_s = generic_filter(rms_s, np.nanmedian, mode='constant', cval=np.nan, size=spatial_average_npix) # create rms noise cube from the tensor product of rms_v and rms_s if verbose: print("Creating rms noise cube (direct tensor product)...") rmscube = SpectralCube(np.einsum('i,jk', rms_v, rms_s), wcs=cube.wcs, header=cube.header.copy(strip=True)) rmscube.allow_huge_operations = cube.allow_huge_operations # correct the normalization of the rms cube if masking_scheme == 'user': mask_n = mask elif masking_scheme == 'simple': rms_n = mad_std(negdata, ignore_nan=True) uplim_n = 3 * rms_n * cube.unit lolim_n = -3 * rms_n * cube.unit mask_n = (((cube - uplim_n) < (0 * cube.unit)) & ((cube - lolim_n) > (0 * cube.unit))) rms_n = cube.with_mask(mask_n).mad_std().value rmscube /= rms_n # apply NaN mask rmscube = rmscube.with_mask(cube.mask.include()) # check unit if rmscube.unit != cube.unit: rmscube = rmscube * (cube.unit / rmscube.unit) return rmscube
fig.set_size_inches(6.5, 6.5) for gal, ax in zip(subtable['NAME'], axlist.flatten()): eta_mb = eta_mb_dict[molecule] degas_cube_name = 'IR5/{0}_{1}_rebase3_smooth1.3_hanning1.fits'.format(gal, molecule) if not os.path.exists(degas_data + degas_cube_name): ax.set_title(gal) ax.text(0.5, 0.5, 'No data',ha='center') continue cube_degas = SpectralCube.read(degas_data + degas_cube_name) cube_degas = cube_degas / eta_mb mask = SpectralCube.read(degas_data + '/masks/{0}_mask.fits'.format(gal)) mask = mask.with_spectral_unit(u.km/u.s, velocity_convention='radio') hdr = mask.header hdr['CTYPE3'] = 'VRAD' mask = SpectralCube(mask.filled_data[:], wcs.WCS(hdr), header=hdr) mask = mask.with_mask(mask.filled_data[:] > 0) mask = mask.spectral_interpolate(cube_degas.spectral_axis) mask = mask.reproject(cube_degas.header) fl = glob.glob(empire_data + 'EMPIRE_{0}_{1}_*.fits'.format(gal.lower(),molecule.lower())) hdulist = fits.open(fl[0]) hdu = sanitize(hdulist[0]) cube_empire = SpectralCube(data=hdu.data, header=hdu.header, wcs=wcs.WCS(hdu.header)) empire_mask = np.isfinite(hdu.data) cube_empire = cube_empire.with_mask(empire_mask) channel_ratio = ((cube_degas.spectral_axis[1] - cube_degas.spectral_axis[0]) / (cube_empire.spectral_axis[1] - cube_empire.spectral_axis[0])).to(u.dimensionless_unscaled).value