def jtok_equiv(self, freq): ''' Return conversion function between Jy/beam to K at the specified frequency. The function can be used with the usual astropy.units conversion: >>> beam = Beam.from_fits_header("header.fits") # doctest: +SKIP >>> (1.0*u.Jy).to(u.K, beam.jtok_equiv(1.4*u.GHz)) # doctest: +SKIP Parameters ---------- freq : astropy.units.quantity.Quantity Frequency to calculate conversion. Returns ------- u.brightness_temperature ''' if not isinstance(freq, u.quantity.Quantity): raise TypeError("freq must be a Quantity object. " "Try 'freq*u.Hz' or another equivalent unit.") try: return u.brightness_temperature(beam_area=self.sr, frequency=freq) except TypeError: # old astropy used ordered arguments return u.brightness_temperature(self.sr, freq)
def test_brightness_temperature(): omega_B = np.pi * (50 * u.arcsec) ** 2 nu = u.GHz * 5 tb = 7.052587837212582 * u.K np.testing.assert_almost_equal( tb.value, (1 * u.Jy).to_value( u.K, equivalencies=u.brightness_temperature(nu, beam_area=omega_B))) np.testing.assert_almost_equal( 1.0, tb.to_value( u.Jy, equivalencies=u.brightness_temperature(nu, beam_area=omega_B)))
def test_brightness_temperature(): omega_B = np.pi * (50 * u.arcsec) ** 2 nu = u.GHz * 5 tb = 7.052590289134352 * u.K np.testing.assert_almost_equal( tb.value, (1 * u.Jy).to_value( u.K, equivalencies=u.brightness_temperature(nu, beam_area=omega_B))) np.testing.assert_almost_equal( 1.0, tb.to_value( u.Jy, equivalencies=u.brightness_temperature(nu, beam_area=omega_B)))
def Snu(Te=default_te, nu=95*u.GHz, R=0.1*u.pc, Qlyc=1e45*u.s**-1, beam=4000*u.au, angular_beam=0.5*u.arcsec): tb = Tb(Te=Te, nu=nu, EM=EM(R=R, Qlyc=Qlyc)) if beam < R: return tb.to(u.mJy, u.brightness_temperature(radio_beam.Beam(angular_beam), nu)) else: return (tb * (R/beam)**2).to(u.mJy, u.brightness_temperature(radio_beam.Beam(angular_beam), nu))
def to_unit(self, final_unit, barea=None, freq=None): input_units = self.physical_units if freq is None: freq = self.obs_frequency if barea is None: beam_area = self.beam_area else: beam_area = barea if self.nmaps == 1: try: x = 1.0 * input_units[0] t = x.to(final_unit, equivalencies=u.brightness_temperature( beam_area, freq)) self.data[:] = t * self.data[:] self.header['TUNIT{0}'.format(1)] = final_unit.to_string() except UnitConversionError: try: x = 1.0 * input_units[0]**(1 / 2) t = x.to(final_unit, equivalencies=u.brightness_temperature( beam_area, freq)) self.data[:] = t * t * self.data[:] self.header['TUNIT{0}'.format( 1)] = final_unit.to_string() + '^2' except UnitConversionError: pass else: for jmap in range(self.nmaps): try: x = 1.0 * input_units[jmap] t = x.to(final_unit, equivalencies=u.brightness_temperature( beam_area[jmap], freq)) self.data[jmap, :] = t * self.data[jmap, :] self.header['TUNIT{0}'.format(jmap + 1)] = final_unit.to_string() except UnitConversionError: try: x = 1.0 * input_units[jmap]**(1 / 2) t = x.to(final_unit, equivalencies=u.brightness_temperature( beam_area[jmap], freq)) self.data[jmap, :] = t * t * self.data[jmap, :] self.header['TUNIT{0}'.format( jmap + 1)] = '(' + final_unit.to_string() + ')^2' except UnitConversionError: pass
def JybeamtoKkms(fluxdict): intensitylist={} t_bright={} dictkeys=fluxdict.keys() for key in dictkeys: temptransdict=fluxdict[key] temptransdictkeys=list(temptransdict.keys()) print(temptransdictkeys) for i in range(len(temptransdictkeys)): if 'restfreq' in temptransdictkeys[i]: continue else: temp=(temptransdict[temptransdictkeys[i]]['flux']/linewidth_vel).to('Jy') #print(temp) equiv=u.brightness_temperature(temptransdict[temptransdictkeys[i]]['freq']) #print(equiv) jy_sr=temp/temptransdict[temptransdictkeys[i]]['beam'] #print(jy_sr) conversion=jy_sr.to(u.K,equivalencies=equiv) t_bright.update({temptransdictkeys[i]:conversion}) #print(conversion) velflux_T=conversion*linewidth_vel d_velfluxT=(temptransdict[temptransdictkeys[i]]['stddev']/conversion)*velflux_T intensityerror.append(d_velfluxT) #print(velflux_T) #print('\n') intensitylist.update({temptransdictkeys[i]:velflux_T}) return intensitylist,t_bright
def test_swapped_args_brightness_temperature(): """ #5173 changes the order of arguments but accepts the old (deprecated) args """ omega_B = np.pi * (50 * u.arcsec) ** 2 nu = u.GHz * 5 tb = 7.052587837212582 * u.K with pytest.warns(AstropyDeprecationWarning) as w: result = (1*u.Jy).to( u.K, equivalencies=u.brightness_temperature(omega_B, nu)) roundtrip = result.to( u.Jy, equivalencies=u.brightness_temperature(omega_B, nu)) assert len(w) == 2 np.testing.assert_almost_equal(tb.value, result.value) np.testing.assert_almost_equal(roundtrip.value, 1)
def convert_jyperbeam_k(v, bmaj=0., bmin=0., fits_img=None): """ calculate the conversion factor from Jy/beam to K ref: http://docs.astropy.org/en/stable/api/astropy.units.brightness_temperature.html#astropy.units.brightness_temperature this code give the same results as miriad imstat :param v: MHz, the freqency of observation :param bmaj: deg, the beam major angle :param bmin: deg, the beam minor angle :param fits_img: optional, the fits image to provide the bmaj and bmin :return: the conversion factor from Jy/beam to K """ if fits_img != None: fits_open = fits.open(fits_img) head = fits_open[0].header bmaj = head['BMAJ'] bmin = head['BMIN'] bmaj = bmaj * u.deg bmin = bmin * u.deg fwhm_to_sigma = 1. / (8. * np.log(2.))**0.5 beam_area = 2. * np.pi * (bmaj * bmin * fwhm_to_sigma**2.) freq = v * u.MHz equiv = u.brightness_temperature(beam_area, freq) return u.Jy.to(u.K, equivalencies=equiv)
def scale_values(cat=None, type=None, cubhd=None): if type == 'imean': # Convert Jy*ch to K km/s if 'RESTFREQ' in cubhd.keys(): freq = cubhd['RESTFREQ'] * u.Hz elif 'RESTFRQ' in cubhd.keys(): freq = cubhd['RESTFRQ'] * u.Hz deltav = cubhd['cdelt3'] / 1000. * u.km / u.s as2 = 1 * u.arcsec**2 kflux = deltav * as2 * cat['flux'].to( u.K, equivalencies=u.brightness_temperature(as2, freq)) cat[type] = kflux / cat['area_exact'] cat[type].unit = 'K km / s' label = 'mean intensity' elif type == 'v_rms': # Convert m/s to km/s cat[type] = cat['v_rms'].to(u.km / u.s) cat[type].unit = 'km / s' label = 'velocity dispersion' elif type == 'v_cen': # convert ch number to km/s cat[type] = 1.e-3 * (cubhd['crval3'] + cubhd['cdelt3'] * (cat['v_cen'] - cubhd['crpix3'])) cat[type].unit = 'km / s' label = 'mean velocity' elif type == 'tmax': label = 'peak temperature' else: label = type return label
def conversion(v, bmaj, bmin): ''' v(GHz),bmaj(deg),bmin(deg),retrun(Jy/beam -> K) ''' if bmaj == bmin: beam_sigma = bmaj * u.deg beam_area = 2 * np.pi * (beam_sigma)**2 freq = v * u.GHz equiv = u.brightness_temperature(beam_area, freq) else: bmaj = bmaj * u.deg bmin = bmin * u.deg fwhm_to_sigma = 1. / (8 * np.log(2))**0.5 beam_area = 2. * np.pi * (bmaj * bmin * fwhm_to_sigma**2) freq = v * u.GHz equiv = u.brightness_temperature(beam_area, freq) return u.Jy.to(u.K, equivalencies=equiv)
def get_cont(header): contfn = paths.dpath('W51_te_continuum_best.fits') beam = radio_beam.Beam.from_fits_header(contfn) cont_Jy = reproject.reproject_interp(input_data=contfn, output_projection=header)[0]*u.Jy cont_K = cont_Jy.to(u.K, u.brightness_temperature(beam, continuum_frequency)) return cont_K
def convert_to_K(radmc_fits_img, distance=5400*u.pc): fh = fits.open(radmc_fits_img) mywcs = wcs.WCS(fh[0].header) pix_area = np.abs(mywcs.celestial.pixel_scale_matrix.diagonal().prod()) * u.deg**2 conv = u.Jy.to(u.K, equivalencies=u.brightness_temperature(pix_area, mywcs.wcs.crval[2]*u.Hz)) fh[0].data *= conv fh[0].header['BUNIT'] = 'K' return fh
def factor_K2JyPixel(self): """ Conversion factor from [K] to [Jy/pixel] """ pixarea = (self.pixelsize * au.arcsec)**2 freq = self.freq * au.MHz equiv = au.brightness_temperature(pixarea, freq) factor = au.K.to(au.Jy, equivalencies=equiv) return factor
def factor_K2JyPixel(self): """ Conversion factor from [K] to [Jy/pixel] """ pixarea = (self.pixelsize * au.arcsec) ** 2 freq = self.freq * au.MHz equiv = au.brightness_temperature(pixarea, freq) factor = au.K.to(au.Jy, equivalencies=equiv) return factor
def convert_jy_to_k(hdul): header = hdul[0].header beam = radio_beam.Beam.from_fits_header(header) name = hdul[0].fileinfo()['file'].name freq = re.search('\d+\.\d+GHz', name).group().rstrip('GHz') freq = float(freq) * u.GHz conv = (1 * u.Jy).to(u.K, u.brightness_temperature(beam, freq)) hdul[0].data = hdul[0].data * conv.value return conv
def convert_jy_kelvin(bmajor,bminor,frequ): beam_major = bmajor*u.arcsec beam_minor = bminor*u.arcsec freq = frequ*u.Hz fwhm_to_sigma = 1./(8*np.log(2))**0.5 beam_area = 2.*np.pi*(beam_major*beam_minor*fwhm_to_sigma**2) equiv = u.brightness_temperature(beam_area, freq) T = (u.Jy.to(u.K, equivalencies=equiv)) return T
def source_line_brightness_temperature(self): """ The surface brightness of the source assuming it is observed with a beam matched to its size and it has ff=1 (this is consistent with the online RADEX calculator) """ #return (self.line_flux * beamsize) # because each line has a different frequency, have to loop it return ((self.source_line_surfbrightness * u.sr).to( u.K, u.brightness_temperature(1 * u.sr, self.frequency)))
def test_jtok(): major = 0.1 * u.rad beam = Beam(major, major, 30 * u.deg) freq = 1.42 * u.GHz conv_factor = u.brightness_temperature(beam.sr, freq) assert_quantity_allclose((1 * u.Jy).to(u.K, equivalencies=conv_factor), beam.jtok(freq))
def test_swapped_args_brightness_temperature(): """ #5173 changes the order of arguments but accepts the old (deprecated) args """ omega_B = np.pi * (50 * u.arcsec) ** 2 nu = u.GHz * 5 tb = 7.052590289134352 * u.K # https://docs.pytest.org/en/latest/warnings.html#ensuring-function-triggers with warnings.catch_warnings(): warnings.simplefilter('always') with pytest.warns(DeprecationWarning) as warning_list: result = (1*u.Jy).to(u.K, equivalencies=u.brightness_temperature(omega_B, nu)) roundtrip = result.to(u.Jy, equivalencies=u.brightness_temperature(omega_B, nu)) assert len(warning_list) == 2 np.testing.assert_almost_equal(tb.value, result.value) np.testing.assert_almost_equal(roundtrip.value, 1)
def convert_to_K(radmc_fits_img, distance=5400 * u.pc): fh = fits.open(radmc_fits_img) mywcs = wcs.WCS(fh[0].header) pix_area = np.abs( mywcs.celestial.pixel_scale_matrix.diagonal().prod()) * u.deg**2 conv = u.Jy.to(u.K, equivalencies=u.brightness_temperature( pix_area, mywcs.wcs.crval[2] * u.Hz)) fh[0].data *= conv fh[0].header['BUNIT'] = 'K' return fh
def test_swapped_args_brightness_temperature(): """ #5173 changes the order of arguments but accepts the old (deprecated) args """ omega_B = np.pi * (50 * u.arcsec)**2 nu = u.GHz * 5 tb = 7.052590289134352 * u.K # https://docs.pytest.org/en/latest/warnings.html#ensuring-function-triggers with warnings.catch_warnings(): warnings.simplefilter('always') with pytest.warns(DeprecationWarning) as warning_list: result = (1 * u.Jy).to(u.K, equivalencies=u.brightness_temperature( omega_B, nu)) roundtrip = result.to(u.Jy, equivalencies=u.brightness_temperature( omega_B, nu)) assert len(warning_list) == 2 np.testing.assert_almost_equal(tb.value, result.value) np.testing.assert_almost_equal(roundtrip.value, 1)
def source_line_brightness_temperature(self): """ The surface brightness of the source assuming it is observed with a beam matched to its size and it has ff=1 (this is consistent with the online RADEX calculator) """ #return (self.line_flux * beamsize) # because each line has a different frequency, have to loop it return ((self.source_line_surfbrightness*u.sr). to(u.K, u.brightness_temperature(1*u.sr, self.frequency)))
def T2I(temperature, v, bmaj, bmin): ''' calculate intensity temperature(K) v(GHz) bmaj(arcsec) bmin(arcsec) return 1 (Jy/beam) ''' fwhm_to_sigma = 1. / (8 * np.log(2))**0.5 beam_area = 2. * np.pi * (bmaj * un.arcsec * bmin * un.arcsec * fwhm_to_sigma**2) freq = v * u.GHz equiv = u.brightness_temperature(freq) return temperature / (u.Jy / beam_area).to(u.K, equivalencies=equiv)
def line_brightness_temperature(self,beamsize): """ Return the line surface brightness in kelvins for a given beam area (Assumes the frequencies are rest frequencies) """ #return (self.line_flux * beamsize) # because each line has a different frequency, have to loop it try: return u.Quantity([x.to(u.K, u.brightness_temperature(beamsize, f)).value for x,f in zip(self.line_flux_density,self.frequency) ], unit=u.K) except AttributeError as ex: raise NotImplementedError("line brightness temperature is not implemented " "without reference to astropy units yet")
def JybeamtoK(beams,data): intensitylist=[] t_bright=[] for i in range(len(data)): temp=(data[i]).to('Jy/beam') #print(temp) equiv=u.brightness_temperature(data.spectral_axis[i]) #print(equiv) jy_sr=temp/beams[i] #print(jy_sr) conversion=jy_sr.to(u.K,equivalencies=equiv) t_bright.append(conversion.value) #print(conversion) #velflux_T=conversion*lwvel #print(velflux_T) #print('\n') #intensitylist.append(velflux_T) return t_bright
def Jy_to_Kelvin(flux, freqs): ''' Convert flux spectrum in Jy/beam to temperature units. Frequency inputs in MHz. Parameters ---------- flux : 1D Array (float) Spectrum over frequency band in Jy freqs : 1D Array (float) Frequencies (in MHz) ''' beam_FWHM = 755.0 / (np.mean(freqs * 0.001)) * u.arcsec beam_area = 2 * np.pi * (beam_FWHM * fwhm_to_sig)**2 freq_MHz = np.mean(freqs) * u.MHz equiv = u.brightness_temperature(beam_area, freq_MHz) T = (flux * u.Jy).to(u.K, equivalencies=equiv) return T, freqs
def get_nhi(sigma, sens, linewidth, beam_maj, beam_min): """ Get N_HI sens at sigma level Inputs: - sigma: Number, significance level for result - sens: Quantity, sensitivity matched to linewidth - linewidth: Quantity, linewidth from N_HI calc - beam_fwhm: Quantity, beam fwhm """ omega_beam = get_beam_area(beam_maj, beam_min) #hitools, hi freq #should maybe define globally? freq = 1420.405752 * u.MHz #convert to brightness temp tb = sens.to(u.K, u.brightness_temperature(freq, beam_area=omega_beam)) #convert to N_HI nhi = 1.823e18 * tb * linewidth / (u.K * u.km / u.s) / (u.cm * u.cm) nhi_sig = sigma * nhi return nhi_sig
def k2jysr(temp, freq): """ Convert K to Jy/sr. Parameters ---------- temp: array-like Brightness temperature in Kelvin freq: float Frequency of the map in MHz Return ------ out: array-like or float Intensity (brightness) in Jy/sr """ ba = 1 * u.sr equiv = u.brightness_temperature(ba, freq * u.MHz) return (temp * u.K).to(u.Jy, equivalencies=equiv).value
def jysr2k(intensity, freq): """ Convert Jy/sr to K. Parameters ---------- intensity: array-like Intensity (brightness) in Jy/sr freq: float Frequency of the map in MHz Return ------ out: array-like or float Brightness temperature in Kelvin """ ba = 1 * u.sr equiv = u.brightness_temperature(ba, freq * u.MHz) return (intensity * u.Jy).to(u.K, equivalencies=equiv).value
def convert_to_casa(hdu): """ Convert a FITS HDU to casa-compatible units, i.e., Jy/beam """ hdu = file_in(hdu)[0].copy() beam = radio_beam.Beam.from_fits_header(hdu.header) if hdu.header['BUNIT'] == 'K': imwcs = wcs.WCS(hdu.header) cfreq = imwcs.sub([wcs.WCSSUB_SPECTRAL]).wcs_world2pix([0], 0)[0][0] hdu.data = u.Quantity(hdu.data, unit=u.K).to( u.Jy, u.brightness_temperature(beam, cfreq * u.Hz)).value elif u.Unit(hdu.header['BUNIT']).is_equivalent(u.MJy / u.sr): hdu.data = u.Quantity(hdu.data, u.Unit(hdu.header['BUNIT'])).to( u.Jy / beam).value elif hdu.header['BUNIT'] != 'Jy/beam': raise ValueError("Header BUNIT not recognized") hdu.header['BUNIT'] = 'Jy/beam' return hdu
def k2jybeam(temp, freq, beam_width): """ Convert K to Jy/beam. Parameters ---------- temp: array-like Brightness temperature in Kelvin freq: float Frequency of the map in MHz beam_width: float The Gaussian FWHM width in degree Return ------ out: array-like or float Intensity (brightness) in Jy/beam """ ba = beam_area(beam_width) * u.Unit('deg2') equiv = u.brightness_temperature(ba, freq * u.MHz) return (temp * u.K).to(u.Jy, equivalencies=equiv).value
def jybeam2k(intensity, freq, beam_width): """ Convert Jy/beam to K. Parameters ---------- intensity: array-like Intensity (brightness) in Jy/beam freq: float Frequency of the map in MHz beam_width: float The Gaussian FWHM width in degree Return ------ out: array-like or float Brightness temperature in Kelvin """ ba = beam_area(beam_width) * u.Unit('deg2') equiv = u.brightness_temperature(ba, freq * u.MHz) return (intensity * u.Jy).to(u.K, equivalencies=equiv).value
def dendrogram_downaddmom_cube(*args, **kwargs): datacube_dt, datacube_dt_header = downsample_addnoise_and_momentmask(*args) datacube_dt_wcs = wcs.wcs.WCS(datacube_dt_header) beam_size = 1/8 * u.deg frequency = 115 * u.GHz d = astrodendro.Dendrogram.compute(datacube_dt, wcs=datacube_dt_wcs, **kwargs) v_scale = datacube_dt_header['cdelt3'] v_unit = u.km / u.s l_scale = datacube_dt_header['cdelt1'] b_scale = datacube_dt_header['cdelt2'] metadata = {} metadata['data_unit'] = u.K metadata['spatial_scale'] = b_scale * u.deg metadata['velocity_scale'] = v_scale * v_unit metadata['wavelength'] = frequency metadata['beam_major'] = beam_size metadata['beam_minor'] = beam_size metadata['vaxis'] = 0 # keep it this way if you think the (post-downsample/transposed) input data is (l, b, v) metadata['wcs'] = datacube_dt_wcs catalog = astrodendro.ppv_catalog(d, metadata, verbose=True) flux = u.Quantity(catalog['flux']) area_exact = catalog['area_exact'].unit*catalog['area_exact'].data # average brightness temperature integrated over area_exact flux_kelvin = flux.to('K', equivalencies=u.brightness_temperature(area_exact, frequency)) # flux integrated over area and velocity flux_kelvin_kms_deg2 = flux_kelvin * metadata['velocity_scale'] * area_exact catalog.add_column(astropy.table.Column(data=flux_kelvin_kms_deg2, name='flux_kelvin_kms_deg2')) return d, catalog, datacube_dt_header, metadata
def jy_to_ksr(freqs): """ Calculate multiplicative factors to convert [Jy] to [K sr]. Parameters ---------- freqs : :class:`astropy.Quantity` or array_like of float (Deprecated) Frequencies, assumed to be in Hz if not a Quantity. Returns ------- Quantity Conversion factor(s) to go from [Jy] to [K sr]. Shape equal to shape of freqs. """ freqs = np.atleast_1d(freqs) if not isinstance(freqs, Quantity): freqs = freqs * units.Hz equiv = units.brightness_temperature(freqs, beam_area=1 * units.sr) conv_factor = (1 * units.Jy).to(units.K, equivalencies=equiv) * units.sr / units.Jy return conv_factor
def to_temperature(self, bmaj: Optional[u.Quantity] = None, bmin: Optional[u.Quantity] = None) -> u.Quantity: """Obtain the intensity axis in temperature units. Args: bmaj: optional; beam major axis. bmin: optional; beam minor axis. Returns: The intensity axis in temperature units. """ # Beam if bmaj is not None and bmin is not None: beam = Beam(bmaj, bmin) elif self.beam is not None: beam = self.beam else: raise ValueError('Cannot convert to temperature units') # Convert equiv = u.brightness_temperature(self.spectral_axis, beam_area=beam) return self.intensity.to(u.K, equivalencies=equiv)
def jtok_equiv(self, freq): ''' Return conversion function between Jy/beam to K at the specified frequency. The function can be used with the usual astropy.units conversion: >>> (1.0*u.Jy).to(u.K, self.jtok_equiv(1.4*u.GHz)) Parameters ---------- freq : astropy.units.quantity.Quantity Frequency to calculate conversion. Returns ------- u.brightness_temperature ''' if not isinstance(freq, u.quantity.Quantity): raise TypeError("freq must be a Quantity object. " "Try 'freq*u.Hz' or another equivalent unit.") return u.brightness_temperature(self.sr, freq)
def load_spectrum(j=6, object='w51e2-tot', npix=1, headerfile='../W51-25GHzcont.map.image.fits', fntemplate='spec-{object}-{j}{j2}-pb.txt',): # convert 6 -> 'six' for use below linename = ammonia_constants.num_to_name[j] * 2 # the beam size is important for determining the brighntess conversion bm = radio_beam.Beam.from_fits_header(headerfile) # read in the file (dumped to text) xx,yy=np.loadtxt(fntemplate.format(object=object, j=j, j2=j if j < 10 else ""), comments="#").T # we want MEAN flux, not SUM yy = yy / npix # x units are in km/s, reference is in Hz xarr = SpectroscopicAxis(xx*u.km/u.s, refX=ammonia.freq_dict[linename]*u.Hz, velocity_convention='radio') sp = pyspeckit.Spectrum(xarr=xarr, data=yy) sp.unit = 'Jy' # compute the typical noise over the -10 to 10 km/s region mean_error = sp.stats((-10,10))['std'] sp.error[:] = mean_error sp.specname = '{0} {1}'.format(object, linename) # Copy the spectrum so we can convert it to Kelvins spK = sp.copy() jytok = ((1*u.Jy).to(u.K, u.brightness_temperature(bm, sp.xarr.refX)).value) sp.header['JYTOK'] = jytok spK.unit = 'K' spK.data = sp.data * jytok spK.error = sp.error * jytok mean_error_k = mean_error * jytok return sp, spK, mean_error, mean_error_k
def density_distribution(densarr, distr, moleculecolumn, tauthresh=0.8, opr=None, line_ids=[], mincol=None, Radex=Radex, **kwargs): """ Compute the LVG model for a single zone with an assumed density *distribution* but other properties fixed. Parameters ---------- dendarr : array Array of densities corresponding to the distribution function distr : array The density distribution corresponding to the density array moleculecolumn : quantity The total column density of the molecule in question. It will be redistributed across the appropriate densities. Units: cm^-2 [this is wrong - each density will assume a too-low optical depth] """ try: np.testing.assert_almost_equal(distr.sum(), 1) except AssertionError: raise ValueError("The distribution must be normalized.") if not line_ids: raise ValueError("Specify at least one line ID") meandens = (densarr*distr).mean() if opr is None: collider_densities = {'H2': meandens} else: fortho = opr/(1+opr) collider_densities = {'oH2':meandens*fortho,'pH2':meandens*(1-fortho)} # Test whether the multi-slab model is reasonable by checking: # if the column was all at the mean density, would any lines be # optically thick? R = Radex(collider_densities=collider_densities, column=moleculecolumn, **kwargs) R.run_radex() if np.any(R.tau > tauthresh): warnings.warn(("At least one line optical depth is >{tauthresh}. " "Smoothing may be invalid.").format(tauthresh=tauthresh)) # set the optical depth from the *mean* density assuming the *total* column tau = R.tau print("Mean density: {0} Optical Depth: {1}".format(meandens, tau[line_ids])) _thc = (2 * constants.h * constants.c).cgs / u.sr _fk = (constants.h * constants.c / constants.k_B).cgs _thc_value = _thc.value _fk_value = _fk.value _u_brightness = (u.erg * u.s**-1 * u.cm**-2 * u.Hz**-1 * u.sr**-1) xnu = R.frequency.to(u.cm**-1, u.spectral()).value linestrengths = [] texs = [] for dens,prob in zip(densarr,distr): if opr is None: collider_densities = {'H2':dens} else: collider_densities = {'oH2':dens*fortho,'pH2':dens*(1-fortho)} R.density = collider_densities try: R.column = moleculecolumn * prob if mincol is not None and R.column < mincol: R.column = mincol R.run_radex() except ValueError as ex: if ex.args[0] == "Extremely low or extremely high column.": if R.column > u.Quantity(1e20, u.cm**-2): raise ex else: texs.append(np.zeros_like(line_ids)+2.73) linestrengths.append(np.zeros_like(line_ids)) continue else: raise ex if hasattr(R, 'radex'): R.radex.radi.taul[:len(tau)] = tau elif hasattr(R, '_data_dict'): R._data_dict['tau'] = tau fk = _fk_value thc = _thc_value with QuantityOff(): ftau = np.exp(-tau) xt = xnu**3 earg = fk*xnu/R.tex bnutex = thc*xt/(np.exp(earg)-1.0) toti_nounit = R.background_brightness*ftau+bnutex*(1.0-ftau) toti = u.Quantity(toti_nounit, _u_brightness) totK = ((toti*u.sr).to(u.K, u.brightness_temperature(1*u.sr, R.frequency))) linestrengths.append(totK[line_ids]) texs.append(R.tex[line_ids]) linestrengths = np.array(linestrengths) texs = np.array(texs) return R, linestrengths, linestrengths.sum(axis=0), texs, tau[line_ids]
import mpl_plot_templates import numpy as np from agpy import fit_a_line import astropy.units as u import common_constants from common_constants import h2co11freq, h2co22freq, etamb_77, rrl, aobeamarea, gbbeamarea from paths import datapath, fpath import matplotlib matplotlib.rc_file("pubfiguresrc") pl.mpl.rcParams["axes.color_cycle"] = [ "#" + x for x in "348ABD, 7A68A6, A60628, 467821, CF4457, 188487, E24A33".split(", ") ] # Have to convert to Jy to compare fairly ktojy111 = (1 * u.K).to(u.Jy, u.brightness_temperature(aobeamarea, h2co11freq)) ktojy77 = (1 * u.K).to(u.Jy, u.brightness_temperature(gbbeamarea, h2co22freq)) aofn = os.path.join(datapath, "W51_Halpha_6cm_cube_supersampled.fits") h112i = ( fits.getdata(os.path.join(datapath, "H110a_integral.fits")) * ktojy111 ) # ,aofn.replace("cube","integrated"))) * ktojy111 h112a = fits.getdata(os.path.join(datapath, "H110a_amplitude.fits")) * ktojy111 h112a.value[h112a == 0] = np.nan h112c = fits.getdata(os.path.join(datapath, "W51_Halpha_6cm_cube_supersampled_continuum.fits")) * ktojy111 h112c.value[h112c == 0] = np.nan h112h = fits.getheader(os.path.join(datapath, "W51_Halpha_6cm_cube_supersampled_continuum.fits")) h77iname = os.path.join(datapath, "H77a_integral.fits") #'W51_h77a_pyproc_integrated_supersampled.fits') h77aname = os.path.join(datapath, "H77a_amplitude.fits") #'W51_h77a_pyproc_integrated_supersampled.fits') h77i = fits.getdata(h77iname) * ktojy77 / etamb_77
def compute_catalog(d, header): """ Computes a catalog on a dendrogram. Parameters ---------- d : astrodendro.dendrogram.Dendrogram Dendrogram on which to compute a catalog header : astropy.io.fits.header.Header Header corresponding exactly to `d.data`. Used for unit and scaling information to calculate flux and world coordinates. Returns ------- catalog : astropy.table.table.Table Catalog describing the structures in dendrogram `d` using units provided in `header`. metadata : dict Explicitly lists unit properties used in `catalog` """ # rough average of North and South telescopes: # see Dame et al. 2001, p. 794. # "The Northern telescope... has a beamwidth of 8'.4 +/- 0'.2.... # The Southern telescope has nearly the same beamwidth to within # the uncertainties: 8'.8 +/- 0'.2" beam_size = 8.5 * u.arcmin frequency = 115.27 * u.GHz # http://www.cv.nrao.edu/php/splat/ # Remember: by this point, the data ought to be in (v, b, l), with FITS header order opposite that if 'vel' not in header['ctype3'].lower(): raise ValueError("CTYPE3 must be velocity - check that the data were permuted correctly") v_scale = header['cdelt3'] v_unit = u.km / u.s l_scale = header['cdelt1'] b_scale = header['cdelt2'] metadata = {} metadata['data_unit'] = u.K metadata['spatial_scale'] = b_scale * u.deg metadata['velocity_scale'] = v_scale * v_unit metadata['wavelength'] = frequency # formerly: (c.c / frequency).to('mm') but now compute_flux can handle frequency in spectral equivalency metadata['beam_major'] = beam_size metadata['beam_minor'] = beam_size metadata['vaxis'] = 0 # keep it this way if you think the (post-downsample/transposed) input data is (l, b, v) metadata['wcs'] = d.wcs catalog = astrodendro.ppv_catalog(d, metadata, verbose=True) if catalog['flux'].unit.is_equivalent('Jy'): # Workaround because flux is computed wrong (see https://github.com/dendrograms/astrodendro/issues/107) flux = u.Quantity(catalog['flux']) area_exact = u.Quantity(catalog['area_exact']) #.unit*catalog['area_exact'].data # average brightness temperature integrated over area_exact flux_kelvin = flux.to('K', equivalencies=u.brightness_temperature(area_exact, frequency)) # flux integrated over area and velocity flux_kelvin_kms_sr = flux_kelvin * metadata['velocity_scale'] * area_exact.to(u.steradian) catalog['flux_true'] = flux_kelvin_kms_sr background_flux_array = np.zeros_like(catalog['flux_true']) # do a clipping -- # this uses the approximation that any given structure's background is well-represented by its lowest-valued pixel, which can get messy sometimes. for i, row in enumerate(catalog): background_kelvins = d[i].vmin * u.K background_flux = background_kelvins * d[i].get_npix() * metadata['velocity_scale'] * metadata['spatial_scale']**2 background_flux_array[i] = background_flux.to(u.K * u.km/u.s * u.steradian).value catalog['flux_clipped'] = catalog['flux_true'] - background_flux_array return catalog, metadata
'Dec': u.deg, } results = photometry(data, mywcs, regs, beam) for name in results: rslt_dict = {line+"_"+key: value for key,value in results[name].items()} if name in all_results: all_results[name].update(rslt_dict) else: all_results[name] = rslt_dict restfrq = header['RESTFRQ'] * u.Hz tbmax = (results[name]['peak']*u.Jy).to(u.K, u.brightness_temperature(results[name]['beam_area'], restfrq)) all_results[name][line+'_peak_brightness'] = tbmax all_results[name][line+"_freq"] = restfrq # invert the table to make it parseable by astropy... # (this shouldn't be necessary....) results_inv = {'name':{}} columns = {'name':[]} colnames = {'name'} # set for k,v in all_results.items(): results_inv['name'][k] = k columns['name'].append(k) for kk,vv in v.items(): colnames.add(kk) if kk in results_inv:
def test_surfacebrightness(): sb = 50*u.MJy/u.sr k = sb.to(u.K, u.brightness_temperature(50*u.GHz)) np.testing.assert_almost_equal(k.value, 0.650965, 5) assert k.unit.is_equivalent(u.K)
#ax3.set_ylabel("Number of sources") #pl.legend(loc='best') #fig2.savefig(paths.fpath('coreplots/mass_histograms.png')) #peak_plot[0].set_visible(False) #H,L,P = ax3.hist(cores_merge['peak_cont_mass'], bins=bins, color='b', # facecolor='none', histtype='step', label='M($20$K)', # linewidth=2, alpha=0.5) #ax3.set_xlim(0,7) #fig2.savefig(paths.fpath('coreplots/mass_histograms_low.png')) # # # # # beam area is for the continuum data beam_area = u.Quantity(np.array(dendro_merge['beam_area']), u.sr) jy_to_k = (1*u.Jy).to(u.K, u.brightness_temperature(beam_area, 220*u.GHz)).mean() m20kconv = float(dendro_merge.meta['keywords']['mass_conversion_factor']['value'].split()[1]) def m20ktickfunc(x): return ["{0:0.0f}".format(y*m20kconv) for y in x] fig4 = pl.figure(4) fig4.clf() ax5 = fig4.gca() #for species in np.unique(dendro_merge['PeakLineSpecies']): # if species != 'NONE': # mask = species == dendro_merge['PeakLineSpecies'] # ax5.plot(dendro_merge['cont_flux0p4arcsec'][mask]-dendro_merge['cont_flux0p2arcsec'][mask], # dendro_merge['peak_cont_flux'][mask], 's', label=species) ax5.plot(dendro_merge['cont_flux0p4arcsec']-dendro_merge['cont_flux0p2arcsec'], dendro_merge['peak_cont_flux'], 'ks', alpha=0.75, label='')
import FITS_tools import os import aplpy import numpy as np from astropy import units as u import pylab as pl #lawfile = os.path.join(datapath,'GCCBand_Brick_zoom_crop.fits') lawfile = os.path.join(datapath,'GCCBand_lb.2.fits') lawdata = fits.getdata(lawfile).squeeze() law_hdr = FITS_tools.strip_headers.flatten_header(fits.getheader(lawfile)) fwhm = np.sqrt(8*np.log(2)) beam = (2*np.pi*u.deg**2*(4.241274E-02)**2/fwhm**2) kperjy = (1*u.Jy).to(u.K, equivalencies=u.brightness_temperature(beam,4.829*u.GHz)) lawdata = lawdata * kperjy.value ccontfile = os.path.join(datapath,'LimaBean_H2CO11_cube_continuum.fits') ccontdata = fits.getdata(ccontfile).squeeze() #ccontdata -= np.nanmin(ccontdata) # HACK ccont_hdr = fits.getheader(ccontfile) brick_mask = fits.getdata(datapath+'brick_mask11.fits').astype('bool') okimg = np.isfinite(ccontdata).astype('float') resampled_law = FITS_tools.hcongrid.hcongrid(lawdata, law_hdr, ccont_hdr) xok = (np.isfinite(ccontdata) * (ccontdata != 0)).max(axis=0) yok = (np.isfinite(ccontdata) * (ccontdata != 0)).max(axis=1)
def K2JyPixel(self): pixarea = (self._pixelsize * au.arcsec) ** 2 equiv = au.brightness_temperature(pixarea, self._freq*au.MHz) return au.K.to(au.Jy, equivalencies=equiv)
Column(data=([cubes[name].wcs.wcs.restfrq for name in cube_names]*u.Hz).to(u.GHz), name='Frequency'), Column(data=[dv[name].to(u.km/u.s).value for name in cube_names]*u.km/u.s, name='Channel Width'), Column(data=[errors[name].to(u.mJy).value for name in cube_names]*u.mJy/u.beam, name='RMS'), Column(data=[beams[name].major.to(u.arcsec).value for name in cube_names]*u.arcsec, name='BMAJ'), Column(data=[beams[name].minor.to(u.arcsec).value for name in cube_names]*u.arcsec, name='BMIN'), Column(data=[beams[name].pa.to(u.deg).value for name in cube_names]*u.deg, name='BPA'), ] ) tbl.add_column(Column(data=[(1*u.Jy).to(u.K, u.brightness_temperature(bm.sr, freq*u.GHz,)).value for bm,freq in zip(beams.values(), tbl['Frequency']) ], name='Jy-Kelvin')) tbl.add_column(Column(data=((tbl['RMS']*u.beam).to(u.Jy).value*tbl['Jy-Kelvin'])*u.K, name='RMS$_K$'), index=4) tbl.sort(['Frequency']) latexdict['header_start'] = '\label{tab:cubes}' latexdict['caption'] = 'Spectral Cubes' latexdict['tablefoot'] = ('\par\nJy-Kelvin gives the conversion factor from Jy ' 'to Kelvin given the synthesized beam size and ' 'observation frequency.') latexdict['col_align'] = 'l'*len(tbl.columns) #latexdict['tabletype'] = 'longtable'
centroid_par='shift', ) myclass.__name__ = "ch3cn_absorption" return myclass pyspeckit.spectrum.fitters.default_Registry.add_fitter('ch3cn_absorption',ch3cn_absorption_fitter(),5) if __name__ == "__main__" and False: import paths cube = SpectralCube.read(paths.dpath('longbaseline/W51e2e_CH3CN_cutout.fits')) sp_ = cube[:,43,43] hdr = sp_.header hdr['BUNIT'] = 'K' sphdu = fits.PrimaryHDU(data=sp_.to(u.K, u.brightness_temperature(cube.beam, cube.wcs.wcs.restfrq*u.Hz)).value, header=hdr) sp = pyspeckit.Spectrum.from_hdu(sphdu) sp.data -= np.percentile(sp.data, 25) sp.plotter() sp.specfit(fittype='ch3cn', guesses=[62, 2, 500, 1e16]) # do it again, excluding k=0 and k=1 sp2 = sp[:400] sp2.plotter() sp2.specfit(fittype='ch3cn', guesses=[62, 2, 500, 1e16]) F = False T = True sp.specfit(fittype='ch3cn_spw', guesses=[62, 2,]+[100]*14 + [0],
""" A 1 mJy source will have T_B = 811.6665408856167 K at 4.9 GHz The upper size limit for a 10^4 K source is 0.030297250253506165 arcsec,or 0.7946490089788438 mpc = 163.9081238701842 AU """ import numpy as np from astropy.io import fits from astropy import units as u import radio_beam import paths from common_constants import distance header = fits.getheader(paths.dpath("W51C_ACarray_continuum_4096_both_uniform_contsplit.clean.image.fits")) beam = radio_beam.Beam.from_fits_header(header) mJytoK = (1*u.mJy).to(u.K, u.brightness_temperature(beam, 4.9*u.GHz)) print("A 1 mJy source will have T_B = {0} at 4.9 GHz".format(mJytoK)) sizelim = (((mJytoK/(1e4*u.K) * (beam.sr))/(2.*np.pi))**0.5).to(u.arcsec) print("The upper size limit for a 10^4 K source is {0}," "or {1} = {2}".format(sizelim, (sizelim*distance).to(u.mpc, u.dimensionless_angles()), (sizelim*distance).to(u.au, u.dimensionless_angles()) ))
w = wcs.WCS(header).sub([wcs.WCSSUB_CELESTIAL]) mask = noisereg.get_mask(header=w.to_header(), shape=im[0].data.squeeze().shape) noise_est[ep] = im[0].data.squeeze()[mask].std() * 1000 peak[ep] = im[0].data.max()*1000 obstbl = Table([Column(data=[ep.split()[-1] for ep in beams], name='Epoch'), Column(data=[float(ep.split()[0]) for ep in beams]*u.GHz, name='Frequency'), Column(data=[bm.major.to(u.arcsec).value for bm in beams.values()]*u.arcsec, name='BMAJ'), Column(data=[bm.minor.to(u.arcsec).value for bm in beams.values()]*u.arcsec, name='BMIN'), Column(data=[bm.pa.to(u.deg).value for bm in beams.values()]*u.deg, name='BPA'), Column(data=[noise_est[ep] for ep in beams]*u.mJy/u.beam, name='Noise Estimate'), Column(data=[peak[ep]/noise_est[ep] for ep in beams], name='Dynamic Range'), ]) obstbl.add_column(Column(data=[(1*u.Jy).to(u.K, u.brightness_temperature(bm.sr, freq*u.GHz,) ).value for bm,freq in zip(beams.values(), obstbl['Frequency']) ], name='Jy-Kelvin' ) ) obstbl.sort(['Frequency', 'Epoch']) latexdict['header_start'] = '\label{tab:observations}' latexdict['caption'] = 'Observations' latexdict['tablefoot'] = ('\par\nJy-Kelvin gives the conversion factor from Jy ' 'to Kelvin given the synthesized beam size and ' 'observation frequency.') #latexdict['col_align'] = 'lllrr'
results_inv['name'][k] = k columns['name'].append(k) for kk,vv in v.items(): if kk in results_inv: results_inv[kk][k] = vv columns[kk].append(vv) else: results_inv[kk] = {k:vv} columns[kk] = [vv] for c in columns: if c in units: columns[c] = u.Quantity(columns[c], units[c]) tbl = Table([Column(data=columns[k], name=k) for k in ['name', 'RA', 'Dec', 'peak', 'sum', 'npix', 'beam_area', 'bgmad', 'peak_90GHz', 'sum_90GHz', 'bgmad_90GHz', 'peak_100GHz', 'sum_100GHz', 'bgmad_100GHz', 'peak_mass_20K', 'peak_col_20K']]) peak_brightness = (tbl['peak']*u.beam).to(u.K, u.brightness_temperature(tbl['beam_area'], masscalc.centerfreq)) tbl.add_column(Column(data=peak_brightness, name='peak_K', unit=u.K)) tbl.sort('peak_mass_20K') tbl.write(paths.tpath("continuum_photometry.ipac"), format='ascii.ipac', overwrite=True)
from astropy.io import fits from astropy import units as u import numpy as np from paths import dpath #f = fits.open('H2CO_11_speccube.fits') f = fits.open(dpath('H2CO_11_speccube_contsub17_big_uniform.image.fits')) beam = (np.pi*f[0].header['BMAJ']*f[0].header['BMAJ']*u.deg**2) cont_offset = (2.7315*u.K).to(u.Jy,u.brightness_temperature(beam, 4.82966*u.GHz)) # try to fix NANs.... this definitely makes everything technically wrong, but more aesthetically useful extra_cont_offset = 0.10 # 0.05 arbitrarily selected to get a decent match... #cont = (f[0].data[0,100:300,:,:].sum(axis=0) + f[0].data[0,600:900,:,:].sum(axis=0)) / 500. + 0.05 cont = fits.getdata(dpath('H2CO_11_speccube_cont_16_18_big_uniform.image.fits')).squeeze() + cont_offset.value + extra_cont_offset cspec = f[0].data[:70,:,:] cspec[cspec > 0] = 0 spec = cspec + cont # try to "subtract out" the negative continuum... spec[:,cont<0] -= cont[cont<0] cont[cont<0] = cont_offset.value + extra_cont_offset # avoid huge NAN splotches #spec[spec<0] = cont_offset.value tau = -np.log((spec/cont)) tau[0,:,:] = cont # just so we have it... that first channel sucked anyway
dd = ds9.ds9() cubes = {name: SpectralCube.read(dpath(fn)) for name,fn in cube_names.items()} vcubes = {name: cube.with_spectral_unit(u.km/u.s, velocity_convention='radio') for name,cube in cubes.items()} beams = {name: radio_beam.Beam.from_fits_header(cube.header) for name,cube in vcubes.items()} for cube in vcubes.values(): cube._unit = u.Jy vkcubes = {name: cube.with_flux_unit(u.K, u.brightness_temperature(beams[name], cube.wcs.wcs.restfrq*u.Hz)) for name,cube in vcubes.items()} for name,vc in vkcubes.items(): vc._header['OBJECT'] = name vc.to_ds9(dd.id, newframe=True) dd.set('tile yes') dd.set('frame frameno 1') dd.set('frame delete') dd.set('scale limits -300 300') dd.set('wcs fk5') dd.set('lock frame wcs') dd.set('lock slice wcs') dd.set('lock scale yes') dd.set('lock color yes')
#ln selfcal_allspw_selfcal_4ampphase_mfs_tclean_deeper_5mJy.image.pbcor.fits W51_te_continuum_best.fits #ln selfcal_allspw_selfcal_4ampphase_mfs_tclean_deeper_5mJy.residual.fits W51_te_continuum_best_residual.fits contfile = fits.open(paths.dpath('W51_te_continuum_best.fits')) data = u.Quantity(contfile[0].data, unit=contfile[0].header['BUNIT']) mywcs = wcs.WCS(contfile[0].header) beam = radio_beam.Beam.from_fits_header(contfile[0].header) pixel_scale = np.abs(mywcs.pixel_scale_matrix.diagonal().prod())**0.5 * u.deg pixel_scale_as = pixel_scale.to(u.arcsec).value ppbeam = (beam.sr/(pixel_scale**2)).decompose().value / u.beam #pl.hist(data[np.isfinite(data)], bins=np.linspace(1e-4,0.1,100)) # over what threshold are we including flux when measuring total masses? threshold = 10*u.mJy/u.beam # threshold above which 20 K is very thick thick_threshold = (20*u.K).to(u.mJy, u.brightness_temperature(beam, masscalc.centerfreq)) / u.beam threshold_column = (threshold * u.beam/u.Jy * masscalc.col_conversion_factor(beam)).to(u.cm**-2) threshold_column = masscalc.dust.colofsnu(nu=masscalc.centerfreq, snu=threshold*u.beam, beamomega=beam.sr).to(u.cm**-2, u.dimensionless_angles()) threshold_density = (masscalc.mass_conversion_factor(20) * (threshold*u.beam).to(u.mJy).value / (4/3.*np.pi) / (beam.sr.value*masscalc.distance**2)**(1.5) / (2.8*constants.m_p)).to(1/u.cm**3) definitely_signal = data > threshold definitely_thick_if_20K = data > thick_threshold total_signal = data[definitely_signal].sum() / ppbeam print("Total pixels > 10mJy/beam: {0} = {1}; r_eff = {2}" .format(definitely_signal.sum(), definitely_signal.sum()/ppbeam, ((definitely_signal.sum()*(pixel_scale*masscalc.distance)**2)**0.5).to(u.pc,